Linux Environment Variables Are Kind Of Weird

แชร์
ฝัง
  • เผยแพร่เมื่อ 16 ธ.ค. 2024

ความคิดเห็น • 284

  • @GameCyborgCh
    @GameCyborgCh 22 วันที่ผ่านมา +445

    "Knock Knock"
    "Race Condition"
    "Who's there?"

    • @SIackware
      @SIackware 22 วันที่ผ่านมา +13

      programmers are also human is such a great channel

    • @NJ-wb1cz
      @NJ-wb1cz 22 วันที่ผ่านมา

      At least there can't be a race condition in "Knock Knock"

    • @Finkelfunk
      @Finkelfunk 22 วันที่ผ่านมา +1

      @@NJ-wb1cz At the end, some instructions are ultimately atomic. Actually accurate meme

    • @Dr-Zed
      @Dr-Zed 21 วันที่ผ่านมา

      this made me chuckle

  • @kuhluhOG
    @kuhluhOG 22 วันที่ผ่านมา +186

    Here's another interesting thing:
    - getaddrinfo is defined as threadsafe
    - getaddrinfo (in glibc) calls getenv
    - getaddrinfo is practically a hard requirement if you want to use IPv6 (if you don't want to implement its logic fully yourself)
    Have fun with that.

    • @SianaGearz
      @SianaGearz 22 วันที่ผ่านมา +11

      Thank you, good case study why you can't avoid or wrap or be smart and careful with getenv. The only way is that setenv shouldn't exist. But it also can't not exist since your dependencies call it.
      OK if steam wanted to be sneaky they could just ld-preload a setenv which always allocates new memory.
      And i get why it's not the default behaviour, since shell interpreters call setenv a lot and long running shell scripts exist.

    • @chaos.corner
      @chaos.corner 22 วันที่ผ่านมา +13

      The correct answer is that getaddrinfo should be fixed or redefined as not thread safe. If not fixed, a thread safe implementation should be used either through local implementation or using another library (this is open source, after all). I'm not sure the logic of why getaddrinfo calls getenv but it might be worth looking into that too.

    • @SianaGearz
      @SianaGearz 22 วันที่ผ่านมา

      @@chaos.corner getaddrinfo must inspect environment variable LOCALDOMAIN for example.
      Making it non-threadsafe is a horrible idea, you're effectively plain forbidding MT networked software, which is not something you can just do especially not all these decads later.
      Unfortunately getenv isn't the only legal way to retrieve an environment variable, you also have an external symbol that is always populated by the executable loader as per POSIX. None of the ways are threadsafe if setenv or putenv is ever called, and are all threadsafe if env is effectively constant.
      So the real problem is that setenv and putenv are garbage that shouldn't exist in MT software. Just compose an explicit environment for child processes with execve and purge all setenv using libraries from MT software, or fix them to not do that.

    • @llothar68
      @llothar68 22 วันที่ผ่านมา +7

      getaddrinfo is a terrible 40 year old solution. We really need some more modern and OS wide service DNS caching solution. Lets put it into systemd.
      But the getenv is no problem at all as modern programming had banned the use of setenv long ago. You never modify, just copy and modify when you start a new process. It's unfixable, just like "select" call.

    • @kuhluhOG
      @kuhluhOG 22 วันที่ผ่านมา +4

      @@llothar68 getaddrinfo under the hood makes use of whatever DNS caching solution the system uses (that can include systemd)

  • @replikvltyoutube3727
    @replikvltyoutube3727 22 วันที่ผ่านมา +104

    The worst thing is that someone may depend on this bug in C

    • @lorenzo42p
      @lorenzo42p 22 วันที่ผ่านมา +11

      it's a grandfathered feature now, can't change it

    • @phantom_stnd
      @phantom_stnd 22 วันที่ผ่านมา +7

      Most certainly, the only way to fix the bug is to return a copy of the string instead, but that would pass the responsibility for dealocating the copy to the caler

    • @lorenzo42p
      @lorenzo42p 22 วันที่ผ่านมา +5

      @@phantom_stnd I agree, but that again means programmers will do things they shouldn't. solves one problem but introduces a new one

    • @thingsiplay
      @thingsiplay 22 วันที่ผ่านมา +6

      Being sometimes correct and sometimes wrong is not a feature.

    • @VivekYadav-ds8oz
      @VivekYadav-ds8oz 21 วันที่ผ่านมา +1

      This makes so much sense now why Rust returns allocated String's whenever you call std::env::args() ​@@phantom_stnd

  • @kolossarthas
    @kolossarthas 22 วันที่ผ่านมา +185

    I'm so early that I got to report fake comments.

    • @0.Andi.0
      @0.Andi.0 22 วันที่ผ่านมา +4

      Yeah, the same

    • @ThePlayerOfGames
      @ThePlayerOfGames 22 วันที่ผ่านมา +7

      Same! Thanks for your work!

    • @tertle950
      @tertle950 22 วันที่ผ่านมา +1

      Hey, same here

    • @danwellington3571
      @danwellington3571 22 วันที่ผ่านมา +2

      ThioJoe made a thing to automate reporting spam comments

    • @Ledplous
      @Ledplous 22 วันที่ผ่านมา +1

      Thanks for that

  • @siberx4
    @siberx4 22 วันที่ผ่านมา +34

    Opting to trigger a memory leak rather than a crash in this scenario seems pretty enlightened; while environment variables can and do change, it's pretty rare that they're changing frequently enough with large enough values that they'd leak a problematic amount of memory in any realistic scenario. Certainly not great, but better than the alternative if you're working with a broken API like this.

    • @SianaGearz
      @SianaGearz 22 วันที่ผ่านมา +5

      Long running shell scripts are an example of programs that can be susceptible, so in linux ecosystem, that may be a breaking change.

    • @RobBCactive
      @RobBCactive 21 วันที่ผ่านมา +1

      ​​@@SianaGearznope, the environment is part of a process's address space created by exec(2), shell scripts can alter the environment for new child processes but it's not a substitute for shared memory.

    • @RobBCactive
      @RobBCactive 21 วันที่ผ่านมา +2

      It's NOT a broken API, the environment is part of the address space of a new process.
      If you are stupid enough to attempt to fake shared memory between threads using environment functions you are simply breaking the C memory model.
      There are no guarantees about what the program will do, memory is copied into different caches and registers to actually be used and application programmers have to know about it.

    • @SianaGearz
      @SianaGearz 21 วันที่ผ่านมา +3

      @@RobBCactive what does shared memory have to do with anything? Shell is single threaded. The child process runs off a fresh cow copy. I'm saying deliberately leaking memory in setenv implementation may cause shell scripts to aggressively leak memory unless shell stops using setenv and moves to execve.

    • @RobBCactive
      @RobBCactive 21 วันที่ผ่านมา +1

      @@SianaGearz because threads share memory, doh.
      Why would glibc have to leak memory in the main process thread? It's only a problem seen by incorrect programs
      I don't agree a band aid is required, the Valve dev quotes are from the point of view of people doing hacks rather than getting client programs fixed.
      People are allowed to write bad code and incorrect programs, they can be ignorant too.

  • @IngwiePhoenix_nb
    @IngwiePhoenix_nb 21 วันที่ผ่านมา +15

    The land of C where all memory is allocated and deallocated by hand,
    and every single bug is either pointers, pointerarithmetic or straight up WTF territory. :D
    I love C. It's whacky, bonkers, but yet a dozen times more stable than JavaScript could ever dream. XD

  • @Miku-Hatsune-b4d
    @Miku-Hatsune-b4d 22 วันที่ผ่านมา +77

    Rust edition 2024 will actually mark setenv unsafe, forcing you to use unsafe to use it.

    • @mtarek2005
      @mtarek2005 21 วันที่ผ่านมา

      can't they reimplement it?

    • @framegrace1
      @framegrace1 21 วันที่ผ่านมา +7

      @@mtarek2005 How the env vars are stored is a standard, nothing anyone can change all by iself.

    • @CYXXYC
      @CYXXYC 21 วันที่ผ่านมา

      @@framegrace1 is it a libc bug or linux bug? in first case you dont need to use libc, and is easily rewritable unless libc is plain syscalls in setenv/getenv implementations

    • @FrankHarwald
      @FrankHarwald 21 วันที่ผ่านมา

      @@mtarek2005 they should really reimplement setenv/getenv from the ABI spec of how the kernel/program loader puts environment variables right above the top of the stack when the process gets fork()'d but this time making it thread safe using some kind of synchronization primitives around them.

    • @ruroruro
      @ruroruro 21 วันที่ผ่านมา +3

      ​@@FrankHarwald the problem is that "the current environment" is a libc concept. You could hypothetically not use libc and just copy the envp before main, but then your copy of the environment wouldn't be synchronized with what other libraries / programming languages see when doing interop. Which would make your "current environment" basically useless.

  • @gljames24
    @gljames24 22 วันที่ผ่านมา +112

    And people say experienced C developers just don't write unsafe code. SMH

    • @linuxguy1199
      @linuxguy1199 22 วันที่ผ่านมา +11

      Code is inherently unsafe.

    • @Finkelfunk
      @Finkelfunk 22 วันที่ผ่านมา

      @@linuxguy1199 Unless you write Haskell where your code is mathematically proven to be safe if it compiles.

    • @chevychavanne4433
      @chevychavanne4433 22 วันที่ผ่านมา +26

      I don't know anyone that can make that statement in good faith. Software is written by humans who make mistakes, and it's language agnostic

    • @khai96x
      @khai96x 22 วันที่ผ่านมา +8

      @@chevychavanne4433 There's a lot of "overly compassionate" criticizers when ever the topic of Rust in the kernel is brought up.

    • @AOSP-is-still-Linux
      @AOSP-is-still-Linux 22 วันที่ผ่านมา +20

      ​@@chevychavanne4433 Some people (the same people that are arguing that memory corruption bugs are "a skill issue") aren't capable of that level of reasoning

  • @R4d1o4ct1v3_
    @R4d1o4ct1v3_ 22 วันที่ผ่านมา +35

    That's it. I'm writing all my code in assembly from now on.

    • @Creepus_Explodus
      @Creepus_Explodus 22 วันที่ผ่านมา +31

      Giga brain move. It can't break if it's never finished

    • @SianaGearz
      @SianaGearz 21 วันที่ผ่านมา

      @@R4d1o4ct1v3_ i hear 6502 is in bloom this time of the year.

    • @kensmith5694
      @kensmith5694 21 วันที่ผ่านมา +1

      Yes that works and indeed every instruction is self documenting and all but if you call someone else's code you are still hosed. You need to do it in the "the whole machine is mine" mode and handle everything your self. Doing disk I/O is a bit more tricky than a lot of other things.

  • @BearOve
    @BearOve 22 วันที่ผ่านมา +43

    Great explanation of why Rust started to mark setenv as unsafe recently

    • @framegrace1
      @framegrace1 21 วันที่ผ่านมา +1

      It should never have been safe in the first place. Is in the docs.

  • @danwellington3571
    @danwellington3571 22 วันที่ผ่านมา +52

    One wonders why the functions aren't marked unsafe :P

    • @thewhitefalcon8539
      @thewhitefalcon8539 22 วันที่ผ่านมา +4

      Because rust is a sham

    • @rose_x86
      @rose_x86 22 วันที่ผ่านมา +35

      everything in C is marked unsafe

    • @BruhKhokhols
      @BruhKhokhols 22 วันที่ผ่านมา +6

      cause everything is unsafe (anyway rust can't fix glibc fault)

    • @danwellington3571
      @danwellington3571 22 วันที่ผ่านมา +23

      @@BruhKhokhols IIRC Rust 2024 is marking the relevant functions as unsafe so yeah Rust can fix it on its end

    • @valeth6472
      @valeth6472 22 วันที่ผ่านมา +9

      set_var is marked as unsafe in rust, I think it's currently only enforced for nightly and the upcoming 2024 edition

  • @GuzikPL4
    @GuzikPL4 22 วันที่ผ่านมา +14

    New bcachefs drama dropped!

    • @BrodieRobertson
      @BrodieRobertson  22 วันที่ผ่านมา +10

      I'm aware, there's a lot

  • @Beryesa.
    @Beryesa. 22 วันที่ผ่านมา +21

    Why do we pretend like POSIX editions can't be updated though, it's not always 1970 there xD

    • @BrodieRobertson
      @BrodieRobertson  22 วันที่ผ่านมา +13

      They can be but this is part of modern POSIX lol

    • @Beryesa.
      @Beryesa. 22 วันที่ผ่านมา +5

      @BrodieRobertson fixed* might be a better word, though it probably needs a little "going back to the whiteboard" action at the very least by this point

    • @Rudxain
      @Rudxain 20 วันที่ผ่านมา

      I wish POSIX shells defined array-literals

  • @nullplan01
    @nullplan01 21 วันที่ผ่านมา +4

    In most cases, you actually don't want to modify your own environment. The places I have seen that change the environment actually want to set a different environment for a child process. POSIX and C don't have functions to do this, so you have to do it yourself, but this way the process environment remains unchanged. Of course, sometimes you do need to adjust TZ or PATH or something, so this isn't universal.

  • @SianaGearz
    @SianaGearz 22 วันที่ผ่านมา +6

    Leaking memory and returning strings that are constant for the rest of program runtime is a completely viable approach to fully safeguard this function family, and given the spec, the only one that is actually robust. Since there isn't just about any software that is long running and updates env all the time.
    OR IS THERE. Indeed there is, shell scripts, particularly long running ones aren't uncommon. To be actually good, shell interpreters should not use setenv, and should just maintain variables on heap, composing them into new process's environment on execution. But they'll probably be like "why should we be smart about this, we aren't multithreaded!"

    • @p0358
      @p0358 18 วันที่ผ่านมา

      Wouldn’t they only do setenv if you called “export” to set them?

    • @SianaGearz
      @SianaGearz 18 วันที่ผ่านมา

      @p0358 yes but scripts which continuously write exported variables are not uncommon.

  • @MarekKnapek
    @MarekKnapek 21 วันที่ผ่านมา +2

    Fork system call was a "virtue of necessity" back in the '70s in PDP days. Just spawn new process and explicitly enumerate what should be inherited into it.

  • @lorenzo42p
    @lorenzo42p 22 วันที่ผ่านมา +8

    here I am being a programmer myself, assuming other programmers are doing things properly. I only access environment variables in the main thread, when the program is starting. process or copy the values and store in a place I know for sure it will be safe. never assume something is thread safe, it probably is not.

    • @moarjank
      @moarjank 22 วันที่ผ่านมา +5

      Good programmers read Docs. Great programmers test their code and don't trust the docs.

    • @lorenzo42p
      @lorenzo42p 22 วันที่ผ่านมา +4

      @@moarjank race conditions can be extremely difficult to find. it's not as simple as testing. program crashes, ok there must be a bug, let me look deeper into this... it's working fine now, I cannot reproduce the bug. what can I do now. as for docs, it's rare I find them to be actually useful. they don't say much beyond the obvious, this function takes these arguments and one line to describe what the function does.

    • @Anohaxer
      @Anohaxer 21 วันที่ผ่านมา +2

      you should check most of your standard library calls also. anything marked "MT-Safe env" or "MT-Safe locale" is calling getenv() or reading the locale and allowed in a threaded context. other libraries certainly call this stuff. obvious stuff like gettext() definitely accesses the environment to see the fuller locale. strftime() might be a little less obvious and more required, you can't by your standards call that in anything but the main thread, which you might really want to do at times. that same thing goes for most time functions. lastly the gethostbyname/getaddrinfo type network functions also use getenv, so you'd have to also prefetch all the IP addresses network connections you're making on the main thread before splitting. it's a little hard to adhere to this.

    • @ivanleonelvera7540
      @ivanleonelvera7540 21 วันที่ผ่านมา

      I'm kind in C++ but would't be possible to overwrite the setenv and getenv functions to make them run in the main thread?

  • @gtsiam
    @gtsiam 21 วันที่ผ่านมา +5

    In rust the issue is closed, because they just made all the *env functions unsafe...
    Which is code for: Idk, you deal with it.

    • @nicholasvinen
      @nicholasvinen 20 วันที่ผ่านมา

      Why didn't they just wrap them with a lock?
      Oh, I guess because then direct calls would be safe but indirect calls via other library functions would still be unsafe. Still, surely libc could add locking inside setenv/getenv to fix it pretty easily.

    • @p0358
      @p0358 18 วันที่ผ่านมา

      @@nicholasvinenLocking would maybe help a bit, but not once you get the env var’s value pointer and it gets invalidated by setenv, since you don’t manage its lifetime after the getenv call. So setenv can either free the old pointer and cause crash or leak it like Mac did. And if you iterate over the whole environment array, then even more so problems are bound to happen…
      The only way to fix it is to make it leak some memory one way or another and then have a fixed versions of the API that’d require you to free a copy of env vars instead of getting the raw original pointer, at the cost of some performance overhead…

  • @rogerdahl0
    @rogerdahl0 22 วันที่ผ่านมา +27

    There are many POSIX calls that are not thread safe. Nothing really special about `setenv` / `getenv`.

    • @martenkahr3365
      @martenkahr3365 22 วันที่ผ่านมา +19

      The problem is how ubiquitous those two are, and how third party libraries rarely flag themselves as "thread unsafe" because they're using those two calls. And of course, many libraries might only be using them indirectly, and their devs might not even be aware that they're pulling in a library that uses setenv/getenv and making themselves thread unsafe. Also, 'getaddrinfo()', a glibc function that is basically unavoidable if you want to do IPv6, uses those two calls and is therefore thread unsafe. The other thread unsafe POSIX calls are generally easier to avoid.

    • @elzabethtatcher9570
      @elzabethtatcher9570 22 วันที่ผ่านมา +6

      Well, maybe POSIX needs to be change to work well with modern tech and expectations. As Brodie said, expecting people to write single threaded code simply because system spec is stuck in nineties is stupid. Likewise, people cannot read all the source code of the modules they import.

    • @pierrecolin6376
      @pierrecolin6376 22 วันที่ผ่านมา +3

      @@elzabethtatcher9570 Dude, it’s completely trivial to create a new module that performs your getenv/setenv operations and wraps a mutex around them. This is 200% skill issue. Also, no, integrating that mutex in getenv and setenv themselves doesn’t solve the problem since that enables TOCTOU conditions.

    • @rogerdahl0
      @rogerdahl0 22 วันที่ผ่านมา +1

      @@elzabethtatcher9570 The programs don't actually have to be single threaded. It's just that multi-threaded programs have to do their own locking, which doesn't seem like an unreasonable requirement to me. There are other common patterns as well, such as delegating all OS interactions to a single main thread. But there has been an effort to extend POSIX for multi-threading, and there are thread safe versions of at least a few of the calls these days.

    • @llothar68
      @llothar68 22 วันที่ผ่านมา

      @@elzabethtatcher9570 POSIX is dead, a dead man can't change.

  • @n1coc4cola
    @n1coc4cola 21 วันที่ผ่านมา +3

    I would never have thought about using these in a multithreaded env. I usually use it at startup in the main thread and then never again.

  • @stephenreaves3205
    @stephenreaves3205 21 วันที่ผ่านมา +2

    I know the C devs kinda poopoo on Rusts embedding of semantics into the type system, but this is an example where it could be used to communicate this hazard. If std::env::var was NOT marked Sync then we'd know it's not safe across threads. Which would then propagate to any libraries that used them and didn't account for this

  • @BigLongRandomNumberNameM-kf9vy
    @BigLongRandomNumberNameM-kf9vy 21 วันที่ผ่านมา +5

    Wow, this is... a real crap API.
    I can understand the original getenv, but adding a setenv without that's supposed to interact with it is just a disaster. They should have made a totally separate, reentrant API for getting/setting stuff in envp.

  • @AlexandreJasmin
    @AlexandreJasmin 21 วันที่ผ่านมา +3

    setenv() being non thread safe is one of my pet peeve. Mixing fork() and threads is another one. It’s too easy to hit a threading lock in the CoW address space.

  • @kensmith5694
    @kensmith5694 21 วันที่ผ่านมา

    The easy way to solve this would be to copy the environment space each time a new thread is spun up. The down side would be that different tasks could then disagree about the value of a variable. A far more difficult way to solve it is to copy as needed only but then you have to keep multiple cores in sync.

  • @vilijanac
    @vilijanac 22 วันที่ผ่านมา +2

    It is a pointer problem. Processes are not a problem, as when one is created copies all variables.

  • @anonymouskitten4715
    @anonymouskitten4715 20 วันที่ผ่านมา +1

    I’ve been having an issue where the library page will just freeze indefinitely after a minute or two. Closing the window and reopening it works for a bit. Notably I only have to close the GUI, I can leave steam open in the systray. Not sure what it’s about, maybe this is related

  • @Poldovico
    @Poldovico 22 วันที่ผ่านมา +1

    I do remember steam crashing more often in the past. Not a crazy amount even before, but it seems to have gone down to almost never

  • @svaira
    @svaira 22 วันที่ผ่านมา +14

    What's really confusing to me is, why we don't use files for this instead. Even magic kernel files (like /proc) are preferable, since going through syscalls means the problems can be much more easily solved. Obviously there were reasons for them at some point, but it shouldn't be to hard to rewird getenv and setenv to a read/write operation on sth like /proc/ID/env instead, shouldn't it?
    (Obviously, the problem is partly in C / posix standard, but we still could have a better getenv2 / setenv2 and hope everyone switches over at least..)

    • @angeldude101
      @angeldude101 22 วันที่ผ่านมา +8

      Files generally need to be closed when you're done, which isn't really any different from just allocating a temporary buffer and then requiring the user to free it later. Not closing the file when you're done is basically the same as just leaking the temporary buffer. Yes, it'll be cleaned up when the program exits, but that could be arbitrarily far away.
      C++ and Rust programmers wouldn't really need to worry about this since they can automatically clean up resources when they go out of scope, but in any other language, this would require garbage collection, which only works for in-memory buffers but not files.

    • @Finkelfunk
      @Finkelfunk 22 วันที่ผ่านมา +4

      There might be several reasons for this. Keep in mind that the POSIX standard is from a time where memory was extremely slow. So reading from actual files was a no go back then because the environment variables are used at runtime quite often, which would SIGNIFICANTLY slow down programs. Now, obviously with virtual filesystems like /proc this is no longer an issue, but POSIX is POSIX. The POSIX standard also doesn't really assume that things are saved to disk or that VFS even exist (keep in mind that Linux is just one of the POSIX compliant systems, not every POSIX system uses a VFS, take MINIX for example).
      Using a /proc/id/env thing is not a specifically great idea imo, because that'd create problems when spawning threads and processes from the application itself (since the child would now need the parent-id to access its proc directory + environment, which, however, might have already been offed making the process an orphan, which will probably trigger a cascade of exception handling that needs to occur that would be costly and REALLY annoying).
      I'm all for some form of globally accessible file in the /proc system though, but to make this compliant with POSIX the standard would be subject to change which can, as I said, mean that some POSIX systems will have heavy performance loss.
      This is an extremely complex subject, but it should have been addressed decades ago.

    • @svaira
      @svaira 22 วันที่ผ่านมา

      @@Finkelfunk I agree that integrating it with POSIX is probably the biggest issue. However, I don't really see that compatibility between Linux and BSD on the lower level is necessary if we could have a new getenv2 or setenv2 call that would be implemented differently on both OSs and just be threadsafe by definition, and Linux could just have that before it gets into POSIX. Fixing the old getenv might not even be possible, but maybe there is a way. For the proc files, I don't even think you need to have the mother process id, you could just have threads or locally spawned processes have the same env file, that is mapped correctly under the open/close and read/write syscalls, so that two threads cannot have it open at the same time, or so that they are synced regardless, or something along those lines. After all, since theyre in VFS, they could just be memory mapped and the kernel just needs to make sure that they don't override each other. We could even have a kind of "env mutex lock" syscall, that would specifically lock this file for read/write operation for any other thread, or something like that. Idk if this is possible in the kernel, but putting it there would probably the easiest since it already has to do the scheduling and syscalls for the os threads to begin with.

    • @Finkelfunk
      @Finkelfunk 22 วันที่ผ่านมา +4

      @@svaira The issue there is now you have two types of setenv that ultimately both need to set global variables for the user. How would you make that threadsafe? How do you sync those? If an application decides to call "legacy" setenv, then the new getenv2 still needs to function, but how will it guarantee interoperability, if setenv doesn't provide multithreading-security?
      Just slapping a 2 at the end and calling it a day isn't the way to go about fixing this issue, especially considering they still need to share the same resource under the hood.
      Yes and no, what if the parent process spawns two new children who each modify the environment? How will you communicate that the environment has changed between them? There's dozens of edge cases you need to think about, remember that we are talking about millions of active users that use this API. This would be an example of an API that is incredibly easy to use wrong again.
      If you let the Kernel clean up environment variables and synchronize them across users, then the Kernel breaches user space because environment variables are not set in Kernel space but are user specific. So now the Kernel manages a file that needs to be synced across the user space, which goes against the entire philosophy of Linux. Adding a syscall to lock a user space file just adds insult to injury in this regard. This also has nothing to do with scheduling, that is a direct interaction with the hardware and that is why that is a kernel job. Setting variables for local programs to run is entirely a user-land task.

    • @NJ-wb1cz
      @NJ-wb1cz 22 วันที่ผ่านมา

      ​​@@Finkelfunk Easy. You don't. New functions write and read their own set of variables.
      Subscribing to changes is trivial, not sure what's the problem here?... Surely C has patters for this, whether it's callbacks or something else.

  • @13thravenpurple94
    @13thravenpurple94 22 วันที่ผ่านมา

    Loved the video! Thank you 👍

  • @MrBasforce
    @MrBasforce 21 วันที่ผ่านมา

    That is a very good explanation.
    It's weird to have this kind of problem in 2024.

  • @GegoXaren
    @GegoXaren 22 วันที่ผ่านมา +1

    Game mode on Steam Deck does not run KDE.
    About your last question: it seems to start faster as of late, if anything.

  • @alixcozmo
    @alixcozmo 22 วันที่ผ่านมา +1

    I remember steam used to(maybe still does idk) crash after a very specific amount of time of having the screenshot manager open(with thousands upon thousands of screenshots)

  • @whtiequillBj
    @whtiequillBj 22 วันที่ผ่านมา +1

    is this a problem in musl libc?

  • @fooboomoo
    @fooboomoo 18 วันที่ผ่านมา

    on a related but different note, i noticed that if I add certain (graphics related) environment variables in /etc/environment in the wrong order, gnome session manager won't start. I never realized that could be relevant and i still don't understand why.

  • @ivesennightfall6779
    @ivesennightfall6779 22 วันที่ผ่านมา +8

    sometimes the bug is glibc using a character input as an array offset
    isalnum(3) iirc

  • @frango_molhado
    @frango_molhado 22 วันที่ผ่านมา

    I learned a lot. Thanks!!

  • @chaos.corner
    @chaos.corner 22 วันที่ผ่านมา

    Yeah, if your libraries do stuff that breaks stuff, it's going to break stuff. That's always been the case.

  • @colto2312
    @colto2312 21 วันที่ผ่านมา

    100% that 'intended behavior' has to change

  • @zxuiji
    @zxuiji 21 วันที่ผ่านมา

    I do have my ideas on how to fix the situation while keeping the semantics, I'd have to do some experimentation 1st though

  • @computerfan1079
    @computerfan1079 21 วันที่ผ่านมา +2

    Couldn't they make a get_env_v2 and deprecate the old ones?

  • @NFvidoJagg2
    @NFvidoJagg2 22 วันที่ผ่านมา +5

    I guess the workaround way i would handle this would be create a threat who's sole job is to manage environment variables for the application. This doesn't fix libraries doing this, but does ensure application code don't add to it.

    • @RobBCactive
      @RobBCactive 21 วันที่ผ่านมา +1

      Correct!
      Yet MT code needs to be sure its libraries are designed to be thread safe.
      Fundamentally you cannot share memory between threads without mechanisms to ensure coherency or undefined behaviour ie an incorrect program will result.
      It seems like using multiple processes that can operate independently and be simultaneous is forgotten by many.
      Changing environment as a replacement for a shared data structure between threads is simply brain-dead. You'll simply serialise the algorithm in any correct program anyway.

  • @SIackware
    @SIackware 22 วันที่ผ่านมา +18

    who is this linux guy I keep hearing so much about

    • @NJ-wb1cz
      @NJ-wb1cz 22 วันที่ผ่านมา +8

      He is your father, Slack

  • @Lantalia
    @Lantalia 17 วันที่ผ่านมา

    At this point, it seems like it would be less effort to patch glibc and purge things relying on (ab)using the unsafe behavior

  • @RightHandedFridge
    @RightHandedFridge 22 วันที่ผ่านมา +3

    I'm so early to this video on some systems but I'm late on others

  • @toxicbubble5
    @toxicbubble5 17 วันที่ผ่านมา

    What if we put all these variables in some sort of registery system /s

  • @andytroo
    @andytroo 21 วันที่ผ่านมา +2

    11:27 - x11, dbus, etc using getenv, a known race-condition read of publicly writable null terminated char**array?
    how come nobody uses this for more *exotic* manipulation of state?

  • @bes12000
    @bes12000 15 วันที่ผ่านมา

    Steam usually works perfectly ..it now throws 2 errors on start up though related to Boxtron, which im confused about, other than that it's been flawless.

  • @medicalwei
    @medicalwei 22 วันที่ผ่านมา +1

    But why envvar is mutable in the first place?

    • @SianaGearz
      @SianaGearz 22 วันที่ผ่านมา

      There is no such thing as something immutable in classic early C, it predates the (leaky) attempts to introduce that.
      Setenv has indeed always been a mistake and it's something that is very apparent retroactively. As in there really isn't a good reason for it other than it just happened that way and was cast into standard by the time someone actually thought about it.

    • @chaos.corner
      @chaos.corner 22 วันที่ผ่านมา +3

      Because it's not envconst?

  • @GegoXaren
    @GegoXaren 22 วันที่ผ่านมา

    Hopefully Florian Weimer's patches land sooner than later.

  • @johnsmith9205
    @johnsmith9205 22 วันที่ผ่านมา +3

    When launching a game that needs env vars set, just spit out a new shell script, chmod it to +x, then run that to launch the game. Bonus points for creating it on tmpfs somewhere. Or /tmp, whatever. Use the same shell script path when you launch every game, you only need one at a time. No need to mess up your whole Steam client's memory address space just for some tiny env vars. If you need global variables in your code (boo!) just use a mutex and use globals, who cares. Or use a config file which you parse every time, I mean Steam is slow enough already, who cares. Don't, I repeat, don't mess up your memory. I mean, once they've figured out that thou shalt not set env vars, then simply don't, let bash handle it.

    • @GrzesiekJedenastka
      @GrzesiekJedenastka 22 วันที่ผ่านมา +2

      Shell scripts are jank. You don't do that, eww. You use an exec from the e group. They said they now do that, so apparently they need to use setenv for something else than launching games, though I do wonder what they need it for.

    • @johnsmith9205
      @johnsmith9205 22 วันที่ผ่านมา

      @@GrzesiekJedenastka Sure, there's probably a recommended proper way, but a shell script is a quick and dirty solution that will work and you can do it right now without changing much code... I think.

  • @tad2021
    @tad2021 20 วันที่ผ่านมา

    Steam needs an official Flatpak. The unofficial one works better than a native install, and much better than any distro package (Snap... just, no...)

  • @CosmicCleric
    @CosmicCleric 22 วันที่ผ่านมา

    such a pain in the behind! Writing multitasking code is

  • @uiopuiop3472
    @uiopuiop3472 21 วันที่ผ่านมา

    misc race conditions shall b treated as a enuscible imo so they can b easier to

  • @insu_na
    @insu_na 21 วันที่ผ่านมา +1

    I still don't fully understand the root cause. In a hypothetical scenario, if I made a component to my application that I'll call "env manager" that runs as a thread/forked process which is responsible for all setenv and getenv calls and is being interacted with through IPC like with zeromq for example, would the issue still occur? Is the environment only allocated for the first process? Or is it more that any one of the threads can "take ownership of" the environment and just once another thread comes along and tries to access it causes segfaults?

  • @doritoschubun
    @doritoschubun 21 วันที่ผ่านมา +1

    Race condition in a financial software project: ☠

  • @michelians1148
    @michelians1148 21 วันที่ผ่านมา +8

    The reality is Linux is not better than Windows at the core. Both OSes have ultra terrible comedy tier APIs.

    • @stefanalecu9532
      @stefanalecu9532 21 วันที่ผ่านมา +1

      Win32 is much better designed than POSIX because it actually had the foresight to avoid some mistakes. It is overall more consistent and pretty reliable. The only thing that it suffers from is that it is bloated because many of the things that Linux relegates to the userland are integrated in Win32 and also has a lot of cruft. But then, so does Linux, but people are trying to pretend they're not actually cosplaying as a 1970s mainframe once you track down the core heritage and POSIX.

  • @WiihawkPL
    @WiihawkPL 22 วันที่ผ่านมา +1

    i bet musl doesn't have this problem because it doesn't support environment variables

  • @ssl3546
    @ssl3546 15 วันที่ผ่านมา

    The library is fine, C was perfect in 1989. The problem is that unqualified people are writing software. These people should not have jobs, full stop.

  • @xard64
    @xard64 22 วันที่ผ่านมา +4

    I've noticed Steam not running (probably crashed) every now and then on my Steam Deck when using the Desktop mode. Curiously I don't remember ever seeing this on my LTS Ubuntu.

  • @FagnerLuan
    @FagnerLuan 22 วันที่ผ่านมา +4

    I had a lot of crashes on steam since I upgraded to Fedora 41 (Fedora 41 is acting weirdly here, not sure why, but my experience is worse in comparison to 40). Then at some day I started using Steam Beta, which fixed the issue.

  • @genstian
    @genstian 22 วันที่ผ่านมา +3

    Set and get them at the start of code, never update them. Think thats been a rule for 20 years? How could any library fuck this up? I suppose its a problem with being allowed to do so.

    • @no_name4796
      @no_name4796 22 วันที่ผ่านมา +2

      Probably because it's convinient? As you can literally use said env vars as global variable, even across files
      Devs tend to choose convinience over stability lol

  • @extrakrantz7154
    @extrakrantz7154 22 วันที่ผ่านมา +1

    Do people actual have problem with Steam crash on Linux

    • @pierrecolin6376
      @pierrecolin6376 22 วันที่ผ่านมา

      Yes. steamwebhelper is by an unfathomable margin the least stable program I’ve ever used. Three quarters of my coredumpctl list is steamwebhelper dying on SIGILL. That’s supposed to be like the most unlikely signal a well written program would raise…

  • @nnaaaaaa
    @nnaaaaaa 21 วันที่ผ่านมา

    the one most terrifying singular word for a programmer is "race condition"

  • @bosch5303
    @bosch5303 22 วันที่ผ่านมา

    There was also that .sh bug where it could delete your homedir

  • @WispOfSoul
    @WispOfSoul 22 วันที่ผ่านมา

    yes

  • @mudi2000a
    @mudi2000a 21 วันที่ผ่านมา

    This sounds like broken by design to me.

  • @KeinNiemand
    @KeinNiemand 21 วันที่ผ่านมา +1

    just use windows

    • @stefanalecu9532
      @stefanalecu9532 21 วันที่ผ่านมา

      POSIX malding, crying and shitting its pants at the fact Win32 is simply better designed

  • @UAVXP
    @UAVXP 22 วันที่ผ่านมา

    Poor linux users

  • @CEOofGameDev
    @CEOofGameDev 22 วันที่ผ่านมา +3

    what if we rewrite setenv in rust tho?

    • @ruroruro
      @ruroruro 21 วันที่ผ่านมา +1

      You can't. This is an API problem, not an implementation problem.
      Forget about setenv/getenv. In POSIX programs can just straight up mutate the char **environ pointer without locking anything. Good luck with implementing a thread safe getenv when the contents of the environment can just change while you are iterating over them.

  • @thingsiplay
    @thingsiplay 22 วันที่ผ่านมา +2

    Rust
    Edit: 5:25 Okay, watching further the video I see even Rust is affected by it because it uses glibc in the backend. However using musl should at least avoid this I assume, but I'm not sure at the moment.

    • @NJ-wb1cz
      @NJ-wb1cz 22 วันที่ผ่านมา +2

      How would rust convert extern non-threadsafe code into threadsafe code?...

    • @thingsiplay
      @thingsiplay 22 วันที่ผ่านมา

      @@NJ-wb1cz I edited the comment already, because at the time of making the initial comment about Rust I didn't know it was using glibc for this function in the back. Rust cannot run unsafe code safely.

    • @m4rch3n1ng
      @m4rch3n1ng 22 วันที่ผ่านมา +2

      rust kind of fixes this, if you only ever use rust code you can freely and safely set environment stuff because it's behind a mutex lock, but the second you call any c code that calls any of the env functions you're fucked as well because (for obvious reasons) the c code doesn't lock the mutex of the rust standard library.
      you kind of have the same issue with go: all of their env access is also mutex protected, until you use cgo and interop with c code. but it's worse in rust because, not only because a lot more people depend on c libraries than in go, but the rust std also calls libc functions that may use the getenv function, for example host resolving is done via libc getaddrinfo, which calls getenv on glibc (but it doesn't on musl).

    • @thingsiplay
      @thingsiplay 22 วันที่ผ่านมา +1

      @@m4rch3n1ng As far as I understand this is not fixable in Rust, when using glibc to set/get environment variables. So it doesn't fix it at all.
      Or is it possible to set environment variables in Rust without using glibc?

    • @ruroruro
      @ruroruro 21 วันที่ผ่านมา +1

      musl doesn't fix this either. This is an API problem, not an implementation problem.
      Forget about setenv/getenv. In POSIX you can just straight up mutate the char **environ pointer without locking anything. Good luck with implementing a thread safe getenv when the contents of the environment can just change while you are iterating over them.

  • @ai-spacedestructor
    @ai-spacedestructor 22 วันที่ผ่านมา

    luckily i never had much crashes to begin with but i have noticed actually over the past few month that the number of times i see an error screen in the client has significantly gone down.

  • @tertle950
    @tertle950 22 วันที่ผ่านมา +10

    Linux in general is kind of weird

  • @tertle950
    @tertle950 22 วันที่ผ่านมา +3

    Thread safety just does not exist.

    • @ikcikor3670
      @ikcikor3670 22 วันที่ผ่านมา +19

      Quite sure that is objectively incorrect

    • @andreyv116
      @andreyv116 22 วันที่ผ่านมา +3

      Retrofitting concurrency safety is hard.

  • @framegrace1
    @framegrace1 21 วันที่ผ่านมา

    THis is not a bug, is a POSIX implementation incompatibility for Linux. Few linux apps will do that because they will use a workarounf, and has not been fixed exactly for the same reasom, everyone knows and there is an easy workaround and libc developers have things more urgent to do.
    Valve is seeing this because they are running code from other OS's where the implementation doesn't break.

  • @soanvig
    @soanvig 21 วันที่ผ่านมา

    ENVIRONMENT variable
    that means a global variable effectively. even a name suggests that.
    surprise surprise: global variables are bad for multithreaded code

  • @notCAMD
    @notCAMD 22 วันที่ผ่านมา +2

    Why is Steam app proprietary?

    • @xXRealXx
      @xXRealXx 22 วันที่ผ่านมา +10

      'cuz it's a DRM

    • @tablettablete186
      @tablettablete186 22 วันที่ผ่านมา

      @@xXRealXx Yes-ish, some Steam games are DRM free and even neeed Sream to run

    • @xXRealXx
      @xXRealXx 22 วันที่ผ่านมา +2

      @@tablettablete186 yes, there are DRM free games on Steam that will even run without Steam, but the big reason for why Steam is proprietary is because it's a kind of DRM. And I'm not aware of any open source DRMs. Plus I doubt Valve would want to make Steam itself FOSS or open source in some other way

    • @tablettablete186
      @tablettablete186 22 วันที่ผ่านมา +1

      @@xXRealXx I see, you're right about it.

  • @uuu12343
    @uuu12343 22 วันที่ผ่านมา

    If you use the operator "&" to run multiple commands in the background (aka async), you have manually setup a race condition

  • @anon_y_mousse
    @anon_y_mousse 21 วันที่ผ่านมา

    One massively glaring error here is that setenv isn't in the C standard library. You're not meant to set environment variables, they should already be set before your program runs. The fact that there are shit programmers who think setting environment variables at runtime is in any way a good idea is sad. It's kind of stupid how many people in the comments are blaming C for non-standard bullshit that people do. It's a shame that people refuse to educate themselves and TH-cam keeps censoring so many of my posts so clearly no one will learn from me, but it's even worse when the only voices allowed to speak do such a sloppy job with little to no research and get basic facts wrong. It's tantamount to spreading misinformation which is something they claim to hate, but in reality they perpetuate that fuckery all on their own.

    • @ruroruro
      @ruroruro 21 วันที่ผ่านมา

      1) setenv is in POSIX, it's technically not in the ISO C standard, but this is an insane position to take, because by that logic, C also doesn't have file descriptors or sockets or a bunch of other stuff. Unless you are doing Windows-only development or are using C for ultra low-level embedded programming, POSIX is a "part" of C for all intents and purposes.
      2) Modifying the environment of the current program without starting a whole new process *is* actually a useful feature. The problem is that the current API is bad, not that the feature itself is fundamentally broken.

    • @anon_y_mousse
      @anon_y_mousse 21 วันที่ผ่านมา

      @@ruroruro Not only is that a stupid point of view to take, but it speaks to how fundamentally bad the industry has gotten that you actually believe what you're saying is in anyway an intelligent thought. First of all, you admit the caveats of such a point of view, which means you're already arguing in bad faith, and from a rather arrogant stance as well because there are other platforms, and they do count. Second of all, if you need to send yourself a message, then you're doing it horribly wrong by using setenv, both at all, and incorrectly for how it functions. Please quit now and go work as a fry cook.

    • @anon_y_mousse
      @anon_y_mousse 21 วันที่ผ่านมา

      @@ruroruro And since TH-cam is playing shenanigans, I'll reiterate that you shouldn't be programming if you're going to take the stance that you are. Go become a fry cook instead of littering the world with shit code from you who is a shit programmer.

    • @anon_y_mousse
      @anon_y_mousse 21 วันที่ผ่านมา

      @@ruroruro Fuck TH-cam for deleting perfectly innocuous posts. Stupid pieces of shit are the kind of idiot programmers that bring us dumbfucks like you who insist on doing things the wrong way and will never be corrected in your idiot thinking because you won't ever see the correction. Go ahead, continue making the world a worse place by writing code that will guaranteed fail. Don't bother learning the correct method of passing messages. Keep thinking that everything POSIX is correct. Although, if you insist on doing these things, the world would be better off if you worked for McDonald's instead.

    • @stefanalecu9532
      @stefanalecu9532 21 วันที่ผ่านมา

      I'm suuuuuuure TH-cam is censoring you, yup, you're right... Brodie comes down with a comically large spoon and scoops out your comments specifically, you're being persecuted for your truly based knowledge. Be real now

  • @RobBCactive
    @RobBCactive 21 วันที่ผ่านมา

    This video should have considered the C memory model rather than blindly repeating what Valve application programmers are saying.
    The hardware lies to you guys!
    You are NOT reading/writing to memory but copies held in caches and registers, so fundamentally accessing shared memory carelessly leads to undefined behaviour, meaning an incorrect program.
    The examples are demonstrations of application programmer incompetence & ignorance, which Valve are working around.

    • @dynfoxx
      @dynfoxx 21 วันที่ผ่านมา +4

      There is no safe way to use the API in C

    • @RobBCactive
      @RobBCactive 21 วันที่ผ่านมา

      @@dynfoxx rubbish!! It's purely a MT issue. You're saying the equivalent that changing any value is unsafe and that includes the parameters of functions in purist languages like Haskell.

    • @ruroruro
      @ruroruro 21 วันที่ผ่านมา +2

      ​@@RobBCactive no, the API is broken, because to use it safely, you have to only interact with the environment while holding a mutex, but the standard doesn't include this mutex. This means that unless your program only runs code that *you* have written (no libraries, no interop between languages, no CFFI) then it is impossible to do so in a thread-safe manner. Because there is no way to make every piece of code to agree on a single locking mechanism to use for accessing the environment. You can tell that this is a practically impossible task, because even glibc itself sometimes gets it wrong internally.

    • @RobBCactive
      @RobBCactive 21 วันที่ผ่านมา +1

      @ruroruro it's not meant to be thread safe, Environment is inherently about processes and passing to child processes.
      You're just advocating that inefficient erroneous poorly designed code should be forced on every program.
      The environment is passed via a char **, like argv so the solution you propose fails. Get/setenv are merely optional wrappers used for convenience and not a substitute for knowledge.

    • @ruroruro
      @ruroruro 21 วันที่ผ่านมา +1

      @@RobBCactive I am perfectly aware that the POSIX API directly exposes char **environ. When I say that the API is broken, I am including **environ in that.
      A thread-safe version of this API would either not expose **environ directly at all (instead requiring you to call a function that would take a mutex, copy the current state of the environment and then return that copy) or the API would expose an "official" mutex that every MT-safe program would be required to hold while interacting with the **environ pointer.
      P.S. please tell me, where exactly in my comment am I advocating for forcing "inefficient erroneous poorly designed code" on every program?