• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1350
  • Last Modified:

Another C Programming Puzzle

void fun(void)
{
/*Do something here so that the main function prints something other than 20 */
}


void main()
{
             int i = 20;
             fun();
             printf("%d", i);
}

Question: What should be the contents of function fun() so that the printf in main prints something other than 20?
0
lemmeC
Asked:
lemmeC
  • 10
  • 6
  • 3
  • +1
1 Solution
 
andrewjbCommented:
Fiddle with the stack to change the 20 to something else. Is asm {} allowed? Not very portable..
0
 
lemmeCAuthor Commented:

>> Is asm {} allowed?
No clue. In fact, I do not know the solution.
For the moment, everything is allowed. :-)
 
0
 
andrewjbCommented:
Platform specified?
0
A Cyber Security RX to Protect Your Organization

Join us on December 13th for a webinar to learn how medical providers can defend against malware with a cyber security "Rx" that supports a healthy technology adoption plan for every healthcare organization.

 
lemmeCAuthor Commented:
Nope, nothing other than the question is specified.

I use Windows 2K on a Pentium with VC++ 6.0 and Turbo-C 2.01. Can also access a HP-UX on a Pentium with gcc on it.
I am looking for a solution which works on atleast one of these compilers.
0
 
andrewjbCommented:
void fun(void)
{
  int x[1];
  x[3] = 20;
}

works on my compiler. If it doesn't on yours, try changing the x[3] to x[2] or x[4] or something.

.. and you'll probably need optimisations off.

0
 
lemmeCAuthor Commented:
Turbo C crashes with that code. Will try it out on VC and gcc.
0
 
andrewjbCommented:
Actually, you could probably try something like..

void fun(void)
{
  int x[1];

  int i;

  for ( i = -10 ; i < 10 ; i++ )
    if ( x[i] == 10 ) x[i] = 20;
}
0
 
lemmeCAuthor Commented:
Great. With some modifications, it worked on all 3 compilers (VC, Turbo C, gcc). Thanks!

Modified program:

void fun(void)
{
  int x[1];

  int i;

  for ( i = -50 ; i < 50 ; i++ )
    if ( x[i] == 20 ) x[i] = 10;  
}
0
 
andrewjbCommented:
Ooops. Sorry. int i=20. I copied that to int i=10 which is why my last one was wrong :-)

Anyway, this isn't guaranteed to work at all. It's naughty, unportable and bad code.

Hope this is a puzzle, and not a real-world programming question!

0
 
lemmeCAuthor Commented:
Its just a puzzle, alright. Asked by my colleague as a challenge.
Anyways, thanks.
0
 
olsworldCommented:
good puzzle and amazing solution. i still wonder how the fun() is changing value of a variable declared in main ()... can any one of you pls throw some light on how it happens???

thanx a ton
0
 
lemmeCAuthor Commented:
olsworld,

>>can any one of you pls throw some light on how it happens?

The local variables of each function (including main) are kept in the function's activation record. The activation records reside in stack memory. In this case, the record for fun() would be adjacent to the record for main(). Andrew's solution searches for the variable i of main in the stack memory adjacent to the array variable x of fun and replaces i's contents with a new value.
Just goes to show how risky it is to use arrays without bounds checking.
0
 
olsworldCommented:
i still wonder why it is not throwing memory leak error as it access the memory allocated to the program. and what if some other memory area also contains same value assigned to the variable declared in main().

is this solution guranteed to work on all platforms and all times? i doubt.
0
 
lemmeCAuthor Commented:
>> is this solution guranteed to work on all platforms and all times?
No, it isn't. As Andrew pointed out, its unportable and dangerous code, and should never be used in serious programs.
0
 
olsworldCommented:
thanx a lot lemmeC for clearing my doubts.
0
 
krkiranCommented:
Hi,

One possible solution is,

void fun(void)
{
  int j;
  *( (int*)((int*)(*(&j+1))-1) )=25;

  /*Explanation for the above statement
    (&j+1) - gives the EBP(Base Pointer) of fun()
    ( *(&j+1) ) - gives the EBP of main which is stored in fun() stack frame.
    ( (int*)(*(&j+1)) -1 ) - converting it into integer pointer and then decrementing it, to get the actual address of 'i' in main()'s stack frame
    *( (int*) ((int*)(*(&j+1))-1)  ) - Again converting it into integer pointer and changing the actual value of 'i' .
  */

}


void main()
{
           int i = 20;
           fun();
           printf("%d", i);
}

You can better use this code which tries to calculate the address of i in fun() and then changes its value. It is working with Linux, but not with Solaris. The stack frame generated by solaris might be different. lemmC, do you know how  stack frame is generated in solaris?

Thanks
Ravikiran
0
 
lemmeCAuthor Commented:
Ravikiran,
       Your code seems good, and your explanation is convincing. But it dumped core on HP-UX. I do not have a Linux system around right now. Will try it out when I get hold of one.

For the Solaris stack frame format, take a look at http://segfault.net/~scut/cpu/sparc/sparcstack/sparcstack.html.

0
 
lemmeCAuthor Commented:
Found a neat (and platform independent) way of doing it.

void fun(void)
{
#define printf(a,b) printf("10");
}

void main()
{
           int i = 20;
           fun();
           printf("%d", i);
}
0
 
andrewjbCommented:
Excellent. Give the points (back) to that man!
0
 
lemmeCAuthor Commented:
No need. Your answer was great too! And I can't accept my own answer as a solution. :-)
0

Featured Post

A Cyber Security RX to Protect Your Organization

Join us on December 13th for a webinar to learn how medical providers can defend against malware with a cyber security "Rx" that supports a healthy technology adoption plan for every healthcare organization.

  • 10
  • 6
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now