4 ms·
Another way to address that problem is to not default initialise at all. There's then no need to worry about a default value for pointers, or about NaN vs. 0.0
by dbaupp 7y ago
Another way to address that problem is to not default initialise at all. There's then no need to worry about a default value for pointers, or about NaN vs. 0.0 for floats.
In addition, null doesn't always give a segfault, as I'm sure you're aware. In C and C++, using (dereferencing) null is undefined behaviour, and a segfault is the best-case result. The code may have been optimised so that there's not a direct dereference (which would segfault) but instead other operations that rely on the pointer being non-null.
- XMPPwocky 7y agoNot to mention "fun" cases like this (contrived example) code- // Read sparse array from file uint64_t len = read_u64(); uint8_t *buf = malloc(len); while (more_data_remaining_in_input_file()) { uint64_t pos = read_u64(); if (pos >= len) { abort(); /* hackers detected! */ } buf[pos] = read_u8(); } which will very reliably compile into a write-what-where primitive when passed a gigantic `len`. malloc() fails and returns NULL (yes, it'll do this even on Linux when virtual address space is exhausted), and nasal demons emerge rapidly from there.
- WalterBright 7y agoWhile this can happen, it's theoretical. In 40 years of dealing with null pointers, I've never seen one happen where the offset is outside the protected null page. The reason is simple - very few allocated objects are that large, and for the arrays that are, they get filled from offset 0 forwards. The real problem with C is not null pointers, it's buffer overflows caused by C arrays inescapably decaying to pointers, so array overflow checks can't be done: https://www.digitalmars.com/articles/b44.html https://www.digitalmars.com/articles/b44.html
- XMPPwocky 7y agoOut of curiosity, have you been trying to make things work, or have you been trying to break things? Because- here's the thing. I've been messing around with software security stuff for 5 years or so, and I've seen exploitable bugs related to a pointer unexpectedly being null twice. There's a big difference between the kind of bugs you find "organically", when somebody's trying to use the software normally, and the kind of bugs you find when you're crafting (or fuzzing) absurd inputs that make no sense and that no ordinary software would produce. Perhaps this is why I've seen more of these bugs despite my much shorter career?
- WalterBright 7y ago> I've seen exploitable bugs related to a pointer unexpectedly being null twice. I've never heard of one, what I hear about endlessly are buffer overflows. Can you give more information about these? I want to learn more.
- XMPPwocky 7y agoYeah, definitely! The one that comes to mind was in a game's texture loader - because of players being able to use custom "spray paint" images, this was exposed to untrusted code. It unpacked mipmaps from a packed texture file into a malloc'd buffer, with an option to skip the first N mipmaps. (If I remember correctly, it'd then go back and upscale the largest mipmap to fill in the ones it skipped.) Mipmaps were stored largest first, consecutively- so the first, say, 512x512xsizeof(pixel) would be the biggest mipmap, then you'd have 256x256xsizeof(pixel) bytes for the second-biggest one, etc, down to some reasonable (i.e. not 1x1px) minimum size. The issue came when a texture's dimensions were specified as being so large that malloc'd fail and return NULL. Normally, this wouldn't be an issue (besides a denial of service) - but by skipping the first N mipmaps, you'd instead write to (where x and y are the dimensions of the texture) def addr(n, x, y, pixel_size_in_bytes=3): out = 0 for i in range(n): out += x*y*pixel_size_in_bytes x >>= 2 y >>= 2 return out By choosing x, y, and N carefully (I used a SMT solver to help) you could overwrite a function pointer and get it called before the later upscaling operation ran (since that would access 0x0 and crash). It's definitely a unique bug, but this sort of thing does happen in real code. Making malloc() and friends panic or similar on failure instead of returning NULL would fix most of these bugs- but it does sort of seem like the whole idea of sentinel values and in-band signalling is hazardous. Go-style 'f, err := os.Open("filename.ext")' has its appeal from that perspective- you can forget to check "err" before doing things with "f", but I assume the Go ecosystem has good tooling to catch that. Also probably worth noting that arguably this bug is related to C arrays being just pointers wearing fancy pants- as long as you can't get a slice where the pointer is NULL but the length is nonzero.
- WalterBright 7y ago