Re: strange output on openbsd C code
On Mon, 19 Mar 2007, Matthew R. Dempsky wrote: On Mon, Mar 19, 2007 at 09:55:04PM -0400, Paul D. Ouderkirk wrote: And because I love to reply to myself, if I compile it with -O3, I can reproduce your results: -O3 enables -fstrict-aliasing, which this program violates. The man page explains in more detail. Yep, it's a bit sad to see all the attempts at explaining the bug. But this one hits the mark. Additionally, while stock gcc enables -fstrict-aliasing with -O2, on OpenBSD -fstrict-aliasing is not enabled with -O2, since experience shows violations of pointer aliasing rules are seen a lot in the wild. See man gcc-local: - The -O2 option does not include -fstrict-aliasing, as this option causes issues on some legacy code. -fstrict-aliasing is very unsafe with code that plays tricks with casts, bypassing the already weak type system of C. So don't play tricks like that unless you really understand the issues involved. -Otto
Re: strange output on openbsd C code
On 2007/03/19 19:12, Gustavo Rios wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. It doesn't do this on any system I've tried it on - i386, amd64: x:8589934593 0,1:1,2 c:2 sparc64: x:8589934593 0,1:2,1 c:2
Re: strange output on openbsd C code
On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; ^ this is bad. always say your types in full. x = 1, x+= (unsigned long long)1 33 ; This sets *(x) to 1, and then sets *(x) (yes, the same one) to 1+(133) p = (void *)x; c = p[0] * p[1]; That is, p[1] == *(x+1) is never getting set to anything. Thus the reason the output is always changing is because p[1] is always pointing at a different, random location in memory that has some previous value. Further, p[1] is not your memory, and it's only by chance that you're not segfaulting. fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } -Nick
Re: strange output on openbsd C code
So, why when i printf p[1], it correctly prints 2? On 3/19/07, Nick ! [EMAIL PROTECTED] wrote: On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; ^ this is bad. always say your types in full. x = 1, x+= (unsigned long long)1 33 ; This sets *(x) to 1, and then sets *(x) (yes, the same one) to 1+(133) p = (void *)x; c = p[0] * p[1]; That is, p[1] == *(x+1) is never getting set to anything. Thus the reason the output is always changing is because p[1] is always pointing at a different, random location in memory that has some previous value. Further, p[1] is not your memory, and it's only by chance that you're not segfaulting. fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } -Nick
Re: strange output on openbsd C code
On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: On 3/19/07, Nick ! [EMAIL PROTECTED] wrote: On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; ^ this is bad. always say your types in full. x = 1, x+= (unsigned long long)1 33 ; This sets *(x) to 1, and then sets *(x) (yes, the same one) to 1+(133) p = (void *)x; c = p[0] * p[1]; That is, p[1] == *(x+1) is never getting set to anything. Thus the reason the output is always changing is because p[1] is always pointing at a different, random location in memory that has some previous value. Further, p[1] is not your memory, and it's only by chance that you're not segfaulting. fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } So, why when i printf p[1], it correctly prints 2? Uhm. Hmm. Well, x is a long long which is 8 bytes right? A void (when doing pointer arithmetic) is taken to only be 1 byte (right?). So p[0] is the first byte of those 8, and p[1] is the second, and due to coincidence and twos-complement encoding it happens to show you the expected numbers. Maybe? But that doesn't explain why the output is always changing. Wait, how is * defined on two voids? That shouldn't even compile (unless it's autocasting to int?). -Nick
Re: strange output on openbsd C code
Le Mon, Mar 19, 2007 at 07:12:24PM -0300, Gustavo Rios ecrivait : I am writing a very simple program but the output change for the c variable value change every time i run it. int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; p = (void *)x; fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); p is the address of x. That address is not supposed to be anything fixed. -- Frank Denis - j [at] pureftpd.org - My geeky blog: http://00f.net
Re: strange output on openbsd C code
No! p sizeof is 4 bytes, p is the frst byt of x, and p + 1 is the 4th byte. Casting is only on attribution of x to p. Realize, p[0] evals to 1 and p[1] evals to 2 as it should be. Only problem relates to p[0] * p[1]. I believe it should (1 * 2), i.e., 2. Not a random value. On 3/19/07, Nick ! [EMAIL PROTECTED] wrote: On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: On 3/19/07, Nick ! [EMAIL PROTECTED] wrote: On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; ^ this is bad. always say your types in full. x = 1, x+= (unsigned long long)1 33 ; This sets *(x) to 1, and then sets *(x) (yes, the same one) to 1+(133) p = (void *)x; c = p[0] * p[1]; That is, p[1] == *(x+1) is never getting set to anything. Thus the reason the output is always changing is because p[1] is always pointing at a different, random location in memory that has some previous value. Further, p[1] is not your memory, and it's only by chance that you're not segfaulting. fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } So, why when i printf p[1], it correctly prints 2? Uhm. Hmm. Well, x is a long long which is 8 bytes right? A void (when doing pointer arithmetic) is taken to only be 1 byte (right?). So p[0] is the first byte of those 8, and p[1] is the second, and due to coincidence and twos-complement encoding it happens to show you the expected numbers. Maybe? But that doesn't explain why the output is always changing. Wait, how is * defined on two voids? That shouldn't even compile (unless it's autocasting to int?). -Nick
Re: strange output on openbsd C code
Whenever a printf fixes everything, it's usually because that forces gcc to put the values on the stack. Without the printf, they're probably in registers and p points to who knows what. If you grok assembly, try objdump on the executable to see what's going on. If you want to multiply the two halves of a long long, I'd suggest shifting and masking it out explicitly instead of using pointer tricks like this. --david On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: No! p sizeof is 4 bytes, p is the frst byt of x, and p + 1 is the 4th byte. Casting is only on attribution of x to p. Realize, p[0] evals to 1 and p[1] evals to 2 as it should be. Only problem relates to p[0] * p[1]. I believe it should (1 * 2), i.e., 2. Not a random value. On 3/19/07, Nick ! [EMAIL PROTECTED] wrote: On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: On 3/19/07, Nick ! [EMAIL PROTECTED] wrote: On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; ^ this is bad. always say your types in full. x = 1, x+= (unsigned long long)1 33 ; This sets *(x) to 1, and then sets *(x) (yes, the same one) to 1+(133) p = (void *)x; c = p[0] * p[1]; That is, p[1] == *(x+1) is never getting set to anything. Thus the reason the output is always changing is because p[1] is always pointing at a different, random location in memory that has some previous value. Further, p[1] is not your memory, and it's only by chance that you're not segfaulting. fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } So, why when i printf p[1], it correctly prints 2? Uhm. Hmm. Well, x is a long long which is 8 bytes right? A void (when doing pointer arithmetic) is taken to only be 1 byte (right?). So p[0] is the first byte of those 8, and p[1] is the second, and due to coincidence and twos-complement encoding it happens to show you the expected numbers. Maybe? But that doesn't explain why the output is always changing. Wait, how is * defined on two voids? That shouldn't even compile (unless it's autocasting to int?). -Nick
Re: strange output on openbsd C code
On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: No! p sizeof is 4 bytes, p is the frst byt of x, and p + 1 is the 4th byte. Casting is only on attribution of x to p. Realize, p[0] evals to 1 and p[1] evals to 2 as it should be. Only problem relates to p[0] * p[1]. I believe it should (1 * 2), i.e., 2. Not a random value. For what it's worth, when I run this code I always get the same (presumably correct) values: [EMAIL PROTECTED]:~ $ ./a.out x:8589934593 0,1:1,2 c:2 [EMAIL PROTECTED]:~ $ uname -rm 4.0 i386 -- -- Paul D. Ouderkirk Senior UNIX System Administrator JadedPixel Technologies [EMAIL PROTECTED] -- laughing, in the mechanism -- William Gibson
Re: strange output on openbsd C code
On 3/19/07, Paul D. Ouderkirk [EMAIL PROTECTED] wrote: On 3/19/07, Gustavo Rios [EMAIL PROTECTED] wrote: No! p sizeof is 4 bytes, p is the frst byt of x, and p + 1 is the 4th byte. Casting is only on attribution of x to p. Realize, p[0] evals to 1 and p[1] evals to 2 as it should be. Only problem relates to p[0] * p[1]. I believe it should (1 * 2), i.e., 2. Not a random value. For what it's worth, when I run this code I always get the same (presumably correct) values: And because I love to reply to myself, if I compile it with -O3, I can reproduce your results: [EMAIL PROTECTED]:~ $ cc -O3 test.c [EMAIL PROTECTED]:~ $ ./a.out x:8589934593 0,1:1,2 c:1387628864 (value of c changes with every execution) -- -- Paul D. Ouderkirk Senior UNIX System Administrator JadedPixel Technologies [EMAIL PROTECTED] -- laughing, in the mechanism -- William Gibson
Re: strange output on openbsd C code
On Mon, Mar 19, 2007 at 08:02:10PM -0400, Nick ! wrote: Wait, how is * defined on two voids? That shouldn't even compile (unless it's autocasting to int?). ``unsigned'' is short for ``unsigned int''. The ``(void *)'' cast is a red herring.
Re: strange output on openbsd C code
On Tue, Mar 20, 2007 at 01:35:28AM +0100, Frank Denis wrote: Le Mon, Mar 19, 2007 at 07:12:24PM -0300, Gustavo Rios ecrivait : I am writing a very simple program but the output change for the c variable value change every time i run it. int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; p = (void *)x; fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); p is the address of x. That address is not supposed to be anything fixed. He never prints p.
Re: strange output on openbsd C code
On Mon, Mar 19, 2007 at 07:12:24PM -0300, Gustavo Rios wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; x = 1, x+= (unsigned long long)1 33 ; p = (void *)x; c = p[0] * p[1]; fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } I run this many times, with other stuff in between, and I always get: $ ./gustavo x:8589934593 0,1:1,2 c:2 Same values for everything, every time. Hmm. -- Darrin Chandler | Phoenix BSD Users Group [EMAIL PROTECTED] | http://bsd.phoenix.az.us/ http://www.stilyagin.com/darrin/ |
Re: strange output on openbsd C code
On Mon, Mar 19, 2007 at 07:17:46PM -0700, Darrin Chandler wrote: On Mon, Mar 19, 2007 at 07:12:24PM -0300, Gustavo Rios wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; x = 1, x+= (unsigned long long)1 33 ; p = (void *)x; c = p[0] * p[1]; fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } I run this many times, with other stuff in between, and I always get: $ ./gustavo x:8589934593 0,1:1,2 c:2 Same values for everything, every time. Hmm. Compile it with -O3. Then enjoy.
Re: strange output on openbsd C code
Gustavo Rios [EMAIL PROTECTED] wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? Bleh, what a depressing thread. Gustavo, why didn't you bother to provide all the relevant info, like that you are foolishly compiling with -O3? Its pretty well known that gcc doesn't always produce correct output when using optimizations more aggressive than -O2. Stop using -O3 and suddenly it prints 2 all the time. Looks like this bug is fixed in gcc 4.2 at least. And what is with the answers being provided guys? Its only 8 lines, and its not that hard to follow. Guessing random answers isn't usually very helpful, maybe reading it and saying there's nothing wrong with that code, are you using compiler optimizations? would work better. At least a few people tried it instead of making up non-existant bugs in the code. Adam
Re: strange output on openbsd C code
On Tue, Mar 20, 2007 at 04:40:08AM +0200, [EMAIL PROTECTED] wrote: Compile it with -O3. Then enjoy. Sure. Then I'll light my hair on fire and put it out with a ballpeen hammer. -- Darrin Chandler | Phoenix BSD Users Group [EMAIL PROTECTED] | http://bsd.phoenix.az.us/ http://www.stilyagin.com/darrin/ |
Re: strange output on openbsd C code
On Mon, Mar 19, 2007 at 09:55:04PM -0400, Paul D. Ouderkirk wrote: And because I love to reply to myself, if I compile it with -O3, I can reproduce your results: -O3 enables -fstrict-aliasing, which this program violates. The man page explains in more detail.
Re: strange output on openbsd C code
On Mon, Mar 19, 2007 at 07:12:24PM -0300, Gustavo Rios wrote: I am writing a very simple program but the output change for the c variable value change every time i run it. What would it be my mistake on the source? Did i forget some thing? #include stdio.h int main(int argc, char **argv) { unsigned long long x, c; unsigned*p; /* stop abusing the comma operator */ x = 1, x+= (unsigned long long)1 33 ; /* Fine, storing random void * pointers in p is allowd */ p = (void *)x; /* * You assume that the in memory representation of an * unsigned [2] looks exactly like unsigned long long and you * expect to access the valid initialized memory of x by * dereferencing p. * * These assumptions are all wrong. */ c = p[0] * p[1]; fprintf(stdout, x:%llu\n, x); fprintf(stdout, 0,1:%u,%u\n, p[0], p[1]); fprintf(stdout, c:%llu\n, c); return 0; } Your program is invalid. Gcc has all rights to fuck it up, -omg-optimized or not. Casts are basically syntactic sugar for (i know what i'm doing, now shut up and stop complaining). Remove the (void *) and compile with -Wall. Tobias
Re: strange output on openbsd C code
On Tue, 20 Mar 2007, Tobias Ulmer wrote: /* * You assume that the in memory representation of an * unsigned [2] looks exactly like unsigned long long and you * expect to access the valid initialized memory of x by * dereferencing p. * * These assumptions are all wrong. */ Indeed. The error is very similar to making assumptions about how the internal structure of x, p and c might relate in the commonly seen: union roach_motel { unsigned long long x; unsigned int p[2]; unsigned char c[8]; } foo; /* draws bugs */ We haven't even scratched the surface of the subtle joys of big-endian addressing schemes (note the plural) or alignment requirements in some architectures. Your program is invalid. Gcc has all rights to fuck it up, -omg-optimized or not. It's not strictly invalid, it just doesn't follow the programmer's intent. This is the most difficult sort of bug to find for the original programmer (code blindness), but a stranger can find it more easily. Now if we take code like the example program, and intersperse a few thousand lines of other code, and break it all up over a hundred functions (and files, and bury the declarations about 5 deep in include files), put half the bug in a library, we have the makings of a Windoze-grade nightmare. Add some conditionals, we can write it so that the problem with uninitialized c only shows up one run in a thousand. 0xDEADBEEF comes to mind... Casts are basically syntactic sugar for (i know what i'm doing, now shut up and stop complaining). Remove the (void *) and compile with -Wall. Some casts are READ MY MIND, DAMN IT!. In this case, we notice that cc -O2 and cc -O3 have different psychic skills. I murmur again about alignment issues, which don't exist for the i386 architecture, as far as I know, except as an optimization. (And certain obscure features of the PeeCee like DMA.) The C standard is full of references to alignment. In some architectures, I believe void *p,*q; p=(long *)1; q=(char *)1; p==q will be false. To the OP: you can't do both bit-wise manipulation and arithmetic and expect the results to be always what you think. Besides endian issues and alignment issues, there can be questions of arithmetic (2s-complement, 1s-complement, and others). The PeeCee has blinded many to the rich diversity of hardware possibilities. Sometimes you just have to drag out the assembler. Dave -- Resistance is futile. You've already been assembled.