I of course know it used to output pointer with arguments.
I read book Writing Secure Code by Michael Howard and David LeBlanc.
One program in book
As others have said, this is undefined behaviour.
But what you see seems to be an admittedly naive but "natural" thing. In most C implementation based on the call stack, function input arguments are pushed onto the stack by the caller, and popped[1] off the stack by the callee. In this particular case, the callee (printf
) seems to blindly pop successive pointer-sized elements, based on how many %p
formatting directives there are in the formatting string, without any form of checking. So instead of popping off the (absent) input arguments, it traverses the stack and "sees" what it's not supposed to see. But this is not always the case for other implementations.
[1] By "popping off" I don't mean destructively removing them from the stack; don't take it literally ;) Most likely what happens under-the-hood is that the input arguments are referenced by an offset from a pointer. But here apparently there's no constraint on how far this offset can get.
It means it will print output in a specific format. In the case of parameter "%p" it will be printed in the memory address format for your system (8 digits, hexadecimal).
In general, %p
is a format specifier to print the pointer (address value), the argument expected is a pointer to void
type.
That said, in your code,
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n");
is undefined behaviour.
As per the printf()
description in the standard, if there are insufficient arguments for supplied format, it's UB.
To quote the standard, C11
, chapter §7.21.6.1
[...] If there are insufficient arguments for the format, the behavior is undefined. .[...]
The code snippet has zero guarantee to produce any valid output.
The behaviour of printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
is undefined since your argument list does not match the input string.
The authors are conjecting that this particular misuse of printf
will inject variables from the current stack, and output their addresses. Sometimes they might be correct. Other times the compiler might eat your cat.