As I said, I have no illusion that my code will continue to work with future compilers, let alone that it will work on other platforms. Do you not see a difference here?bob wrote:Sorry, but not allowed. You've been carping about MY using undefined behavior for days now. Isn't this just a tad inconsistent? You use it because it works? You use it in spite of it being called "undefined behavior"?
A note for C programmers
Moderators: hgm, Rebel, chrisw
-
- Posts: 5566
- Joined: Tue Feb 28, 2012 11:56 pm
Re: A note for C programmers
-
- Posts: 5566
- Joined: Tue Feb 28, 2012 11:56 pm
Re: A note for C programmers
If you have full control over the compiler, it does not matter much whether you follow the standard or not. As long as you know what you're doing.Henk wrote:I don't know if my operating system Windows 8 uses elements with undefined behavior. I don't feel safe now.
-
- Posts: 5566
- Joined: Tue Feb 28, 2012 11:56 pm
Re: A note for C programmers
Why don't read before you respond:bob wrote:You need to pull out an intel manual.
The C99 standard guarantees nothing about how a 64-bit int is written to memory. On x86-64 it makes sense to use a single store, which will then be atomic provided it does not cross cache lines. But if the only thing you know about a compiler is that it complies with C99, you don't know that it will use single stores and even if it does, you don't know that it will properly align 64-bit ints.syzygy wrote:You keep confusing things. What the standard guarantees is one thing. What one would naively expect knowing the architecture of a particular machine is another thing. What a particular compiler actually will do is yet something else.
Duh? There is no reason that any particular C library or OS kernel must have been written in C or must have been compiled with the compiler you're using. It may have been written entirely in assembly. Certainly the Linux kernel will NOT properly run when compiled with just any C99 compliant compiler.If a compiler does what you suggest, I/O is impossible. How can I write to a buffer, and signal another thread or process to write that out to disk, so that only one process does I/O? Yet the operating system, the libraries, and everyone else depends on that happening. There is a BIG difference between writing to a local variable, and writing to a global (shared) variable. The compiler is NOT free to optimize away stores/writes to global data.
-
- Posts: 5566
- Joined: Tue Feb 28, 2012 11:56 pm
Re: A note for C programmers
Is it really difficult to understand that the C standard has a very precise definition, which is very different from this one? You can go complain to the drafters of the standard, but it won't change a thing.bob wrote:Since one of the ongoing quibbles here is about the definition of "undefined behavior", here is the usual definition. One that has been used since the 1950's in fact. "Behavior that can not be predicted." This has ALWAYS been an issue of unexpected results caused, NOT by the compiler intentionally doing something off-the-wall, but by the code the compiler produces, which might not always do the expected thing.
-
- Posts: 5566
- Joined: Tue Feb 28, 2012 11:56 pm
Re: A note for C programmers
And it's all concisely expressed in imposes no requirements. If demons start flying through your nose, that is compliant with the standard, because you can't violate "no requirements".rbarreira wrote:On planet earth, you didn't even read properly what you quoted:bob wrote:The standards does not adequately define "undefined behavior" To wit:Rein Halbersma wrote:You are the only one quibbling with the Standard's definition of UB. Everyone else is on the same page here. Don't pull in whatever colloquial speech you are using into a precise and exact definition used by every compiler writer.bob wrote: Since one of the ongoing quibbles here is about the definition of "undefined behavior", here is the usual definition. One that has been used since the 1950's in fact. "Behavior that can not be predicted." This has ALWAYS been an issue of unexpected results caused, NOT by the compiler intentionally doing something off-the-wall, but by the code the compiler produces, which might not always do the expected thing.
UB is about the freedom of a compiler to translate your C code to machine instructions.
3.4.3
1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
EXAMPLE An example of undefined behavior is the behavior on integer overflow.
So it can ignore the situation, to behaving in a documented way (both of which make sense) to terminating the compilation with a message. No mention of demons flying out one's nose or anything else.
So how about we get back to planet earth.
"ignoring the situation completely with unpredictable results" OR "behaving during translation or program execution in a documented manner"
So yes, demons flying out of one's nose are a possible case of undefined behavior.
Last edited by syzygy on Sat Dec 07, 2013 10:36 pm, edited 1 time in total.
-
- Posts: 900
- Joined: Tue Apr 27, 2010 3:48 pm
Re: A note for C programmers
Simple logic is apparently lost on Robert. Either that or he's trolling us.syzygy wrote:And it's all concisely expressed in imposes no requirements. If demons start flying through your nose, that is compliant with the stanard, because you can't violate "no requirements".rbarreira wrote:On planet earth, you didn't even read properly what you quoted:bob wrote:The standards does not adequately define "undefined behavior" To wit:Rein Halbersma wrote:You are the only one quibbling with the Standard's definition of UB. Everyone else is on the same page here. Don't pull in whatever colloquial speech you are using into a precise and exact definition used by every compiler writer.bob wrote: Since one of the ongoing quibbles here is about the definition of "undefined behavior", here is the usual definition. One that has been used since the 1950's in fact. "Behavior that can not be predicted." This has ALWAYS been an issue of unexpected results caused, NOT by the compiler intentionally doing something off-the-wall, but by the code the compiler produces, which might not always do the expected thing.
UB is about the freedom of a compiler to translate your C code to machine instructions.
3.4.3
1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
EXAMPLE An example of undefined behavior is the behavior on integer overflow.
So it can ignore the situation, to behaving in a documented way (both of which make sense) to terminating the compilation with a message. No mention of demons flying out one's nose or anything else.
So how about we get back to planet earth.
"ignoring the situation completely with unpredictable results" OR "behaving during translation or program execution in a documented manner"
So yes, demons flying out of one's nose are a possible case of undefined behavior.
-
- Posts: 5566
- Joined: Tue Feb 28, 2012 11:56 pm
Re: A note for C programmers
Maybe something triggered undefined behavior in Bob?wgarvin wrote:I have an alternative explanation for the last few days of this thread that makes it suddenly make sense to me!
Bob doesn't really believe the things he's saying about undefined behavior, but he has figured out that we get indignant and he's having too much fun trolling us to stop!
-
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: A note for C programmers
You did a strcpy(s, s+40) where s points to knowledge from 1973.syzygy wrote:Maybe something triggered undefined behavior in Bob?wgarvin wrote:I have an alternative explanation for the last few days of this thread that makes it suddenly make sense to me!
Bob doesn't really believe the things he's saying about undefined behavior, but he has figured out that we get indignant and he's having too much fun trolling us to stop!
-
- Posts: 5566
- Joined: Tue Feb 28, 2012 11:56 pm
Re: A note for C programmers
How to miscompile programs with "benign" data races
The example in 2.1 reads as if it was taken from my code...
What I wrote:
The problem is that the compiler might reorder statements and execute "init_flag = true" / "ptr->ready = 1" before initialisation has finished. For this to happen in my code, init_table_wdl() would have to be inlined, but nothing is stopping the compiler from doing just that. The if() statement complicates things only a little bit.
What I need to do is insert a memory barrier just before "ptr->ready = 1":
This ensures that "ptr->ready = 1" is executed after the initialisation has finished.
Alternatively, I could always take the TB_mutex lock, but that could kill performance. Introducing a "ptr->lock" would be only slightly better.
So I'm really not writing standard C here. I am using gcc features to write my own synchronisation primitives.
(Note that even if the compiler does not reorder things, the processor might. This cannot happen on x86 though, as x86 guarantees that memory writes are observed by other processors / cores in the order they were made.)
The example in 2.1 reads as if it was taken from my code...
Code: Select all
if (!init_flag) {
lock();
if (!init_flag) {
my_data = ...;
init_flag = true;
}
unlock();
}
tmp = my_data;
Code: Select all
if (!ptr->ready) {
LOCK(TB_mutex);
if (!ptr->ready) {
char str[16];
prt_str(pos, str, ptr->key != key);
if (!init_table_wdl(ptr, str)) {
ptr2[i].key = 0ULL;
*success = 0;
UNLOCK(TB_mutex);
return 0;
}
ptr->ready = 1;
}
UNLOCK(TB_mutex);
}
What I need to do is insert a memory barrier just before "ptr->ready = 1":
Code: Select all
__asm__ __volatile__ ("" ::: "memory");
Alternatively, I could always take the TB_mutex lock, but that could kill performance. Introducing a "ptr->lock" would be only slightly better.
So I'm really not writing standard C here. I am using gcc features to write my own synchronisation primitives.
(Note that even if the compiler does not reorder things, the processor might. This cannot happen on x86 though, as x86 guarantees that memory writes are observed by other processors / cores in the order they were made.)
-
- Posts: 741
- Joined: Tue May 22, 2007 11:13 am
Re: A note for C programmers
https://www.usenix.org/legacy/event/hot ... /Boehm.pdf
Great paper!
Great paper!
Although data races essentially have no defined semantics
in C or C++, they are perfectly meaningful in
x86 assembly code [17]. An assembly program with a
data race is not necessarily an error. In fact synchronization
primitives are commonly implemented with assembly
code that has data races.
However, we argue here that such a distinction is not
useful if the data race existed in a C or C++ which
was then compiled, and the code was intended to be
portable.3 Not only is the original source code technically
incorrect in such cases, future recompilation of the
code by reasonable compilers may realistically introduce
bugs.