Boschko
Boschko

Reputation: 374

the stack's role with format strings

Okay this is going to be somewhat lengthy.

So I've got a program that uses two %n format parameters in it's a printf() statement. %n essentially writes data without displaying anything... So when my format function encounters %n parameter, it writes the number of bites that have been written by the function to the address of the corresponding function argument.


#include <stdio.h>
#include <stdlib.h>

 int main() {

 int A = 5, B = 7, count_one, count_two;

 printf("The number of bytes written up to this point X%n is being stored in
 count_one, and the number of bytes up to here X%n is being stored in
 count_two.\n", &count_one, &count_two);

 printf("count_one: %d\n", count_one);
 printf("count_two: %d\n", count_two);

 printf("A is %d and is at %08x. B is %x.\n", A, &A, B);

 exit(0); 
 } 

the output of the program is:

The number of bytes written up to this point X is being stored in count_one,and the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at bffff7f4. B is 7.

With regards to this printf

printf("A is %d and is at %08x. B is %x.\n", A, &A, B);

Now, the arguments are pushes to the stack in reverse order first the value of B then the value address of A then the value address of A, and finally the address of the format string...

Now if only two arguments are pushed to the stack with a format string that uses three format parameters?

So I removed the last argument in the code above to match this printf() argument

printf("A is %d and is at %08x. B is %x.\n", A, &A);

and what happens when I compile and execute is...

The number of bytes written up to this point X is being stored in count_one, and the number of
bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at bffffc24. B is b7fd6ff4

So I get this b7fd6ff4, what is that? What does this mean with relations to the stack frame for the format function?

Any insight or explanation would be much appreciated.

Upvotes: 0

Views: 1345

Answers (4)

user3629249
user3629249

Reputation: 16540

the following proposed code:

  1. fixes the problems listed in the comments to the question
  2. cleanly compiles
  3. performs the desired functionality

and now the proposed code:

#include <stdio.h>
#include <stdlib.h>

int main( void )
{
    int A = 5;
    int B = 7;
    int count_one;
    int count_two;

    printf("The number of bytes written up to this point X%n is being stored"
        " in count_one, and the number of bytes up to here X%n is being"
        " stored in count_two.\n",
        &count_one,
        &count_two);

    printf("count_one: %d\n", count_one);
    printf("count_two: %d\n", count_two);

    printf("A is %d and is at %p. B is %x.\n", A, (void*)&A, B);

    exit(0);
}

a typical run of the program results in:

The number of bytes written up to this point X is being stored in count_one, and the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at 0x7fff19c28ea8. B is 7.

Upvotes: 1

dernst
dernst

Reputation: 72

printf assumes that you pushed all 4 arguments on the stack. It is expecting B to be on the stack regardless of whether you provided it or not. If you did not provide it then it will use whatever is in that memory location and print it.

Upvotes: 0

David
David

Reputation: 1694

Under the 32-bit x86 calling convention all function parameters are passed on the stack. If you call printf() with more format specifiers than arguments the function will gladly keep walking up the stack and grabbing whatever values are there to find something to display.

The specific contents of the stack are going to be variable- usually function-local variables, function return pointers, or stack pointers.

Upvotes: 0

dbush
dbush

Reputation: 223992

Having either the wrong number of format specifiers or mismatched format specifiers invokes undefined behavior.

From section 7.21.6.1 of the C standard regarding the fprintf function:

9 If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

What this means is that you can't make any reliable prediction about what value the function will receive if you don't pass it enough parameters. What will most likely happen in an implementation that uses a stack and has optimizations disabled is that it will grab whatever value happens to be next in memory next to the last parameter pushed onto the stack.

Upvotes: 2

Related Questions