3 ms·
Yeah... but I wouldn't characterize the bug itself (in its essential form) as UB. Even if the implementation specified that the data would be indeterminate dep
by torstenvl 9mo ago
Yeah... but I wouldn't characterize the bug itself (in its essential form) as UB.
Even if the implementation specified that the data would be indeterminate depending on what existed in that memory location previously, the bug would still exist.
Even if you hand-coded this in assembly, the bug would still exist.
The essence of the bug is uninitialized data being garbage. That's always gonna be a latent bug, regardless of whether the behavior is defined in an ISO standard.
- forrestthewoods 9mo agoYeah I agree. This is a classic “uninitialized variable has garbage memory value” bug. But it is not a “undefined nasal demons behavior” bug. That said, we all learn this one! I spent like two weeks debugging a super rare desync bug in a multiplayer game with a P2P lockstep synchronous architecture. Suffice to say I am now a zealot about providing default values all the time. Thankfully it’s a lot easier since C++11 came out and lets you define default values at the declaration site!
- titzer 9mo agoI prefer language constructs define that new storage is zero-initialized. It doesn't prevent all bugs (i.e. application logic bugs) but at least gives deterministic results. These days it's zero cost for local variables and near-zero cost for fields. This is the case in Virgil.
- kevin_thibedeau 9mo agoC & C++ run on systems where it may not be zero cost. If you need low latency startup it could be a liability to zero out large chunks of memory.
- ablob 9mo agoI think it's acceptable to leave an escape hatch for these situations instead of leaving it to easy to misunderstand nooks and crannies of the standard. You don't want to zero out the memory? Slap a "foo = uninitialized" in there to have that exact behavior and get the here be demons sign for free.
- forrestthewoods 9mo agoYeah this issue is super obvious and non-controversial. Uninitialized state is totally fine as an opt-in performance optimization. But having a well defined non-garbage default value should obviously be the default. Did C fuck that up 50 years ago? Yeah probably. They should have known better even then. But that’s ok. It’s a historical artifact. All languages are full of them. We learn and improve!
- deleted 9mo ago[deleted]
- 1718627440 9mo agoI don't know, I expect all variables to be uninitialized until proven otherwise. It makes it easier for me to reason about code, especially convoluted code. But I also like C a lot and actually explicitly invoke UB quite often, so there is that.
- forrestthewoods 9mo agoI like C and it's great. I wish more people wrote C instead of C++. But there's a reason that literally no modern language makes this choice. If uninitialization was opt-in you would still be free to "assume uninitialized until proven otherwise". But uninitialized memory is such a monumental catastrophic footgun that really is not a justifiable reason to make that default behavior. Which, again, is why no modern languages make that (terrible) design choice.
- 1718627440 9mo agoI am talking about random convoluted code, I did neither wrote nor control. The UB does not only help the compiler, it also helps me the reverse engineer, since I also can assume that an access without a previous write is either a bug, or I misinterpreted the control flow.
- 9mo ago
- andrewaylett 9mo agoThat makes things worse if all-zero is not a valid value for the datatype. I'd much prefer a set-up that requires you to initialise explicitly. Rust, for example, has a `Default` trait that you can implement if there is a sensible default, which may well be all-zero. It also has a `MaybeUninit` holder which doesn't do any initialisation, but needs an `unsafe` to extract the value once you've made sure it's OK. But if you don't have a suitable default, and don't want/need to use `unsafe`, you have to supply all the values.