0

So, I have an assignment that I need help on. I am given the code for a function called foo() and a function called recover(). I am unable to alter the code for foo, and recover cannot have any arguments, and returns nothing.

The goal of this is to have recover grab the local variables from foo and print them out.

Example:

long foo(long a, long b, long c, long d, long e){
   long x, y, z;
   if(e < 0)
   {
      recover();
      return a;
   }
   //do various things with a, b, and c, and store in x, y, and z respectively
   return foo(x,y,z,d+1,e-1)+a+b+c+d+e;
}

void recover(void)
{
   //What goes here to get the values?
}

What recover() is supposed to do is get the a,b, and c value from EACH call of foo() and print it out. I also know that global variables aren't allowed for this problem.

Thanks for any assistance with this problem.

  • 3
    Lucky you: You get to look at the stack. Stack layout isn't identical across platforms, so we can't give you a single canonical answer that always works. – Charles Duffy Nov 10 '15 at 20:41
  • 3
    I mean, it's not even identical across all architectures Linux supports. Depends on *exactly* your CPU and instruction set, and sometimes even on your compiler's configuration (some extensions to make stack-smashing attacks harder can significantly modify the layout). Easiest thing to do is to ask the compiler to dump the assembly it's generating for your code and read it -- or inspect at runtime with a debugger. – Charles Duffy Nov 10 '15 at 20:43
  • See http://stackoverflow.com/questions/20059673/print-out-value-of-stack-pointer to get an idea of where to start looking in memory from. – Charles Duffy Nov 10 '15 at 20:47
  • 2
    Some of these variables might also end up in registers rather than the stack. –  Nov 10 '15 at 20:47
  • 2
    @Rhymoid, good point; the function isn't an `extern`, so the compiler could just choose to inline the invocation altogether, and not bother with storing locals on the stack. Though `foo` is recursive, and I don't know if C compilers are smart enough to do TCO these days... – Charles Duffy Nov 10 '15 at 20:49
  • 1
    @CharlesDuffy In some popular ABIs (x86-64 for both SysV and Microsoft) the first few arguments must be passed through registers. Even if `foo` is not inlined, the arguments might not ever leave the register file. –  Nov 10 '15 at 20:57
  • @CharlesDuffy: It is not a recursive tail call because it has to do the sum after the return of the recursive call. Anyway if the compiler were smart enough it could detect the use of uninitialized variables, invoke UB and optimize out the recursive call. – rodrigo Nov 10 '15 at 22:43
  • @rodrigo I thought TCO is often accompanied by transformations to end up with a recursive tail call. Unless I'm missing something, I'd think that this can be easily (thus mechanically) turned into a TCO-suitable function. –  Nov 11 '15 at 01:45
  • @Rhymoid: Yes, but and tail recursive call must be the very last operation in te function (`return foo(...);`), while OP code does the recursive call, then a sum and then returns. The transformation needed to apply TCO will imply adding a function argument to pass on the accumulated value, and I don't think any current compiler will dare do that. – rodrigo Nov 11 '15 at 08:47
  • @rodrigo I'd be surprised if no compiler would appropriately transform functions for TCO, but would do SSA transformations for CSE. –  Nov 11 '15 at 09:12

2 Answers2

2

Warning: the following code is highly compiler/architecture dependent and non-compliant. Use it at your own risk.

Local variables are stored in the stack, so you can get to the local variables of the parent function by just declaring a local variable yourself and moving around.

First add some easy-to-spot values to your variables (you'll remove them later)

long foo(long a, long b, long c, long d, long e){
   long x=11111, y=22222, z=33333;
   ...

Probably you are using a PC, so your stack grows down and your targets are up the stack. Just look around until you find them:

void recover(void)
{
    long p;
    long *q = &p;
    for (int i=0; i < 20; ++i)
    {
        printf("%d -> %ld\n", i, q[i]);
    }
}

Or you can use a debugger, of course!

rodrigo
  • 94,151
  • 12
  • 143
  • 190
0

Sounds like a stack hacking exercise.

Try defining a local variable, taking the address, then modifying that address to go down the stack (either adding or subtracting, depending on your machine) until you end up pointing to the variables in the calling function.

This is very system dependent, so you'll need to do some playing around it figure it out. I'd suggest calling foo with a known set of arguments and looking specifically for those values to make sure you're looking in the right place. Once you figure that out, you'll have the values for any call to foo.

dbush
  • 205,898
  • 23
  • 218
  • 273