Earlier quoted context omitted.
A common class assignment or interview question is to write your own memcpy. Towards the end you usually start optimizing it by copying multiple bytes at once. That is undefined behavior. You cannot just cast a pointer to uint32_t* and start using it, unless the underlying object is actually uint32_t. In practice it works fine, so people don't care. We'll see what future compilers will do, especially when the homemad…
You can cast from char* to uint32_t* and start using it. I forget the exact standardese, but there is an execption for char*.
I Do Not Know C: Short quiz on undefined behavior (2015)
151–160 of 189 posts
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#152Earlier quoted context omitted.
If you don't like the "ridiculous" standard, maybe you shouldn't be writing the language that it defines. There are plenty of discussions online what parts of the standard should be changed to get a "friendly C" [1], unfortunately there is no consensus that could be implemented. [1] http://blog.regehr.org/archives/1287
My prediction is that the standard will eventually follow the change in practice and eliminate that compiler "optimization".
1. The program successfully reads/writes that memory location and retrieves/overwrites whatever is there without crashing. Then the program can continue on and execute the if even if the pointer was null.
2. The program crashes immediate whenever a null pointer is read/written.
#1 is problematic, because NULL is a single pointer value that can be applied to a variety of pointer types. What happens if you first write to (long )NULL and then read from (FILE )NULL?
#2 is very useful, and most platforms already crash any program that tries to read or write NULL. But if the standard requires this behavior, then this introduces an even stronger guarantee that a dereferenced pointer is not null, so there's no reason to remove that optimization.
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#153Earlier quoted context omitted.
It means that empty loops (loops with empty bodies) can be completely removed if the controlling expression has no side effects. > This is intended to allow compiler transformations such as removal of empty loops even when termination cannot be proven. It means while(i) {} can be eliminated as if i were 0, because there are no side effects in the loop expression or the loop body, and what would be the point of the lo…
It's quite common in embedded systems to have the fault handler end with an infinite loop, to give the programmer a chance to attach a debugger an inspect the call stack. Sometimes this behavior is turned on or off with a debug flag, which can trigger this unexpected optimization if the flag is not a compile time constant.
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#154Earlier quoted context omitted.
Under what set of logic does being able to de-reference a pointer confer that it's value is not 0 (which is what the test equates to)? Normal deductive logic? * No NULL pointer can be dereferenced. * x is dereferenced. * Therefore, x is not a NULL pointer. Of course, the compiler is presuming that your code is correct. That's a reasonable presumption when dealing with computer programming languages. Programming langu…
* No NULL pointer can be dereferenced. NULL pointers CAN be dereferenced, it all depends on the environment you run on.
There are environments that either lack memory protection and do not allow invalid pointer derereferences to be caught, which means that you can't rely on the MMU to catch mistakes. In this case either deal with silent errors or get a compiler that is able (at a cost) to sanitize any pointer access.
There are other systems in which memory address 0 is a perfectly valid address. The ABI of these systems should pick a different bit pattern for NULL pointers, but often don't so compilers sometime offer as a conforming extension extension the option to allow null pointers to be treated as valid (in effect not having null pointers at all).
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#155Earlier quoted context omitted.
It means that empty loops (loops with empty bodies) can be completely removed if the controlling expression has no side effects. > This is intended to allow compiler transformations such as removal of empty loops even when termination cannot be proven. It means while(i) {} can be eliminated as if i were 0, because there are no side effects in the loop expression or the loop body, and what would be the point of the lo…
It's quite common in embedded systems to have the fault handler end with an infinite loop, to give the programmer a chance to attach a debugger an inspect the call stack. Sometimes this behavior is turned on or off with a debug flag, which can trigger this unexpected optimization if the flag is not a compile time constant.
if (flag) while (1);Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#156Earlier quoted context omitted.
You can cast from char* to uint32_t* and start using it. I forget the exact standardese, but there is an execption for char*.
There is an exception for accessing any object through a character type pointer, but not the other way around. uint32_t is not a character type, and it doesn't matter if it was casted to a char* first. Also, apparently uint8_t may not be a character type.
I think that goes hand-in-hand with the fact that `char` is not guaranteed to be 8-bits wide in C, so by that fact `uint8_t` may not be a `char`. In practice I highly doubt this distinction really matters: Platforms without an 8-bit `char` are basically guaranteed to not support (a standards compliant) `uint8_t` anyway, and it is reasonable to target 8-bit `char` systems in which case it's safe to assume `uint8_t` and `char` are the same thing. (Well, `unsigned char`)
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#157Earlier quoted context omitted.
There is an exception for accessing any object through a character type pointer, but not the other way around. uint32_t is not a character type, and it doesn't matter if it was casted to a char* first. Also, apparently uint8_t may not be a character type.
> Also, apparently uint8_t may not be a character type. I think that goes hand-in-hand with the fact that `char` is not guaranteed to be 8-bits wide in C, so by that fact `uint8_t` may not be a `char`. In practice I highly doubt this distinction really matters: Platforms without an 8-bit `char` are basically guaranteed to not support (a standards compliant) `uint8_t` anyway, and it is reasonable to target 8-bit `char…
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#158Earlier quoted context omitted.
It's quite common in embedded systems to have the fault handler end with an infinite loop, to give the programmer a chance to attach a debugger an inspect the call stack. Sometimes this behavior is turned on or off with a debug flag, which can trigger this unexpected optimization if the flag is not a compile time constant.
You could always say if (flag) while (1);
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#159Earlier quoted context omitted.
My prediction is that the standard will eventually follow the change in practice and eliminate that compiler "optimization".
In order to do that, the standard would have to define that dereferencing a null pointer must produce a deterministic behavior. There are only two possible behaviors: 1. The program successfully reads/writes that memory location and retrieves/overwrites whatever is there without crashing. Then the program can continue on and execute the if even if the pointer was null. 2. The program crashes immediate whenever a null…
Re: I Do Not Know C: Short quiz on undefined behavior (2015)
#160Earlier quoted context omitted.
the post that brought this to my attention discussed how a security error in Linux was created by this "optimization".
This? http://blog.regehr.org/archives/970 The compiler didn't create a security bug by removing the null check. The bug was created by the programmer when he didn't check for null before dereferencing the pointer. Even with the check, the program contained a bug.