tags:

views:

262

answers:

5

Hi,

when i tried to run compile and execute this statement in a simple c file:

main(){ printf("%d");}

on HP it's is giving me 64 and on AIX its giving me 804359524.

Could anyone tell me what is this behavior.

+2  A: 

The code is exposing Undefined Behavior. On other systems it might print "Stack Overflow", (seriously!). %d tells the CRT library that you'll provide an integer, but you don't.

MSalters
I don't think you'll ever get a stack overflow in that code - the stack is not growing.
Skizz
The trigger for a stack overflow is typically a memory access to the stack guard page. printf() could trigger that access when it fails to read the %d integer, and instead hits the guard page. And since it's not a write, you can't solve it by adding another page. It's reasonable for an OS to print "stack overflow" whenever there's any unfixable stack guard page violation; it'll be 99% correct
MSalters
I think that in this case, the value printed is going to be either the return address from the printf function, a register value or perhaps something from main's stack frame depending on the implementation of the compiler and the OS it's running on. I always thought a 'stack overflow' was when the stack had run out of memory when trying to store data on the stack, never when reading data.
Skizz
If we assume the C ABI (where parameters are pushed onto the stack right to left). The skizz is correct and it is unlikely to produce a stack overflow (more likely the return address). But that's a big assumption.
Martin York
Not a big assumption, the question is tagged C and C++.
Skizz
"_The_ C ABI" - is there such a thing? Many platforms define one, which is pretty much proof to the contrary.
MSalters
+20  A: 

I assume you mean:

int main()
{
  printf("%d");
}

That being the case, printf() is reading an int (as directed by the format specifier %d) from the stack. Since you've not specified one, it's just reading whatever is on the stack and using that. Hence, your seeing pseudo-random output.

Instead, try:

int main()
{
  printf("%d", 10101);
}

HTH

dcw
A: 

My guess is that you compile

main(){ printf("%d");}

This will pick a random value off the current stack. Try this:

main() {
   printf("%d", 0);
   printf("%d");
}

Now, the second printf() will always print 0 since it gets the same stack as the first call.

[EDIT] This doesn't work on x86 Linux with GCC 4.1.2. Here is the generated assembler code (use gcc -S -o t.s t.c):

    movl    $0, %esi
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf

As you can see, the second argument isn't pushed on the stack but passed via %esi (which is a register). That same register is probably modified in printf() which is why it's losing its value. Damn optimizations ;)

Aaron Digulla
Wouldn't surprise me if you'd get 1. printf returns the number of arguments consumed. This return value could overwrite the stack.
MSalters
I doubt that for two reasons: a) On most machines, the return value is in a register and b) it would overwrite the format string if it was passed on the stack if it wasn't saved in a different place by the ABI.
Aaron Digulla
Aaron, running that with the intel icc compiler gives a warning about the second printf and an output of 04204818 (0 and 4204818)
Glen
@Glen: Odd. The second printf() should use the same stack addresses as the first and I see no reason to overwrite the second argument :/ Do you have "mungwall" options active or something that trashes unused memory?
Aaron Digulla
@Glen: I found it; see my edits :) Damn the optimizations.
Aaron Digulla
@AAron, no special options were turned on. ">icc x.cc" where x.cc just has the above code.
Glen
+11  A: 

This is classic undefined behavior. The compiler doesn't check that you provide enough arguments to match your formatting string. There are compilers that do this (gcc is one), but yours doesn't.

The code in printf() will happily step through its given formatting string, and when it gets to the "%d" it will read off one int-sized argument (typically: from the stack), not knowing there is no argument there for it to read.

Whatever value happens to be on the stack gets printed.

unwind
+2  A: 

Some compilers, like gcc, will catch this type of oh so common problems if you specify a high enough warning level. Like this (compiling you code, with -Wall - all warnings) :

gcc    -c -g -Wall -MMD -MP -MF build/Debug/Cygwin-Windows/newmain.o.d -o build/Debug/Cygwin-Windows/newmain.o newmain.c
newmain.c: In function `main':
newmain.c:16: warning: too few arguments for format

This is one of around 998 good reasons to always compile with a high warning level, and to take the warning messages seriously.

fvu