1
\$\begingroup\$

This was given to me by a friend of mine, it prints out 0 through 9. We have been quite puzzled over this. Does anyone know why this works?

#include <iostream>

using namespace std;

void x(int a)
{
    *(&a-1) += a;
}

int main()
{
    for(int i = 0; i < 10; ++i)
    {
        x(8);
        i = 0;
        cout << i << endl;
    }
}
\$\endgroup\$

closed as off topic by dmckee Dec 12 '11 at 23:50

Questions on Code Golf Stack Exchange are expected to relate to programming puzzles or code golf within the scope defined by the community. Consider editing the question or leaving comments for improvement if you believe the question can be reworded to fit within the scope. Read more about reopening questions here. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 2
    \$\begingroup\$ CodeGolf.SE is a place to post programming contests with well defined winning conditions. This would, perhaps have been better on Stack Overflow. \$\endgroup\$ – dmckee Dec 12 '11 at 23:52
  • 1
    \$\begingroup\$ @dmckee I would have thought that "Programming puzzles" in the title would reference stuff like this. Sorry :) \$\endgroup\$ – Ólafur Waage Dec 13 '11 at 10:40
  • \$\begingroup\$ Imho, this clearly belongs here, not stackoverflow, the closure reflects badly on the moderator. \$\endgroup\$ – Jeff Burdges Dec 24 '11 at 6:54
  • \$\begingroup\$ void(int a) is never printed. That function is just garbage. What is actually being printed is variable i: cout << i << endl; i is started at 0: int i = 0;, then is incremented by 1: ++i;, as long as it is less than 10. The call x(8) does nothing and is unnecessary. \$\endgroup\$ – Hosch250 Mar 10 '14 at 0:43
9
\$\begingroup\$

First of all, the line *(&a-1) += a; is undefined behavior, so this could do anything depending on compiler version, flags used, alignment of the stars, etc.

That said, the reason why it works in your case is probably because &a-1 happens to point to the return address of x, and incrementing it by 8 causes the i = 0; to be skipped.

\$\endgroup\$
  • 3
    \$\begingroup\$ oh my god... that's nasty. \$\endgroup\$ – Ólafur Waage Dec 12 '11 at 12:34
  • \$\begingroup\$ in other words a buffer overflow without the buffer (or a 1 element buffer) \$\endgroup\$ – ratchet freak Dec 12 '11 at 23:31
3
\$\begingroup\$

The reason this works is because your compiler passes the a parameter on the stack. Before the parameter, the code pushes the return address of the method onto the stack:

004A0008 | 00000008 ; a parameter
004A0004 | 00401200 ; return addr
004A0000 | ...

The &a part of the expression points to the address of the parameter on the stack, in this case I've used 004A0008. The a-1 then subtracts sizeof(int) from that address, giving you 004A0004. The * dereferences that address, so its value can be edited. This means that when you add 8 to the value at 004A0004, it alters the return address. When the method returns, it ends up 8 bytes ahead of where it should have been, skipping the i=0.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.