Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This code is not legal C. <code>main</code> must take either zero, two, or three parameters. One parameter is not a legal option. <code>gets</code> scribbles over the stack. Quite frankly, it's a miracle if this works at all - undefined behavior abounds!</p> <p>With that said, let's look at the typical way C code is compiled on x86 to understand how this works. First, <code>main(i)</code> is an old, K&amp;R-style declaration. It is interpreted as <code>int main(int i)</code>, but does not set up a true prototype - so future calls to <code>main</code> won't have their arguments typechecked. Recall that on x86, arguments are passed by pushing them to the stack just before calling the target function. So if we have the wrong number of arguments, it won't crash (assuming you're on this kind of ABI!), but simply give bogus data.</p> <p>Also note that on x86, the stack grows downward - as you call functions, the current stack pointer <em>decreases</em>. This means that if you corrupt memory above one of these parameters, you'll be corrupting memory belonging to the <em>calling function</em>, and might not notice until you return.</p> <p>Now let's look at the flow of execution. <code>gets(&amp;i)</code> is executed first, and (assuming the compiler ignores the type mismatch!) obtains a line of text, and stores it <em>onto the stack overwriting the caller's stack frame!</em> This assumes a stack that grows downward in memory; on upward-growing stacks this will, depending on the length of the string, overwrite the return address of <code>gets</code> and probably crash.</p> <p>Although <code>gets</code> grabbed a line of text, this text will be ignored and discarded. This is because the return value of <code>gets</code>, which is <code>&amp;i</code>, will be passed to <code>scanf</code>. So <code>scanf</code> reads an integer and stores it in <code>i</code>. No problem. <code>scanf</code> then returns <code>1</code>, which is binary negated to some negative nonzero value, which is true, so <code>printf</code> then prints the value. The comma operator then serves to recursively call main again, with the wrong number of arguments (the argument will typically be initialized with some bogus value), which acts as a loop.</p> <p>Note that after <code>scanf</code> returns, a newline remains in the input unconsumed, so <code>gets</code> deals with that next time around. Also note that when EOF occurs, <code>scanf</code> will return EOF (0xFFFFFFFF), which will be logically negated to 0. <code>main</code> will then return, and promptly crash because its caller's stack has probably been overwritten by <code>gets</code>.</p> <p>All in all, a neat hack, but highly dependent on undefined behavior. Please don't imitate this in real code.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload