setrecursionlimit

Christian Gollwitzer auriocus at gmx.de
Wed May 18 14:11:37 EDT 2016


Am 18.05.16 um 19:15 schrieb Steven D'Aprano:
> Not being a C programmer, I don't really understand this.
>
> The idea I have in mind is a model of program memory I learned[1] way back
> in the 80s. I don't know if it's still valid. Your application has a bunch
> of memory available, which broadly speaking can be divided into three
> chunks: globals, the stack, and the heap.
>
> The application knows what globals exist, and can allocate a fixed block of
> memory big enough for them, so that's not very interesting. It just sits
> there, holding space for the globals, and doesn't grow or shrink.
>
> Then there's the stack, which holds local variables whenever a function is
> called, the return address of the caller, and other stuff. There's a fixed
> bottom to the stack, but the top can grown and shrink depending on how many
> functions you call and how many local variables they use.

Until here, it is reasonably accurate. On some machines, the stack does 
grow in the other direction, but that does not matter either. ON x86, it 
grows from top to bottom

> Then there's everything else, which is the heap, and it can grown and shrink
> in both directions (up to some maximum, of course):
>
> bottom [ globals | stack ----->      <----- heap -----> ] top
>
> If the stack grows into the heap, or vice versa, Bad Things happen. At best
> you get a crash. At worst you get arbitrary code execution.

No, you have virtual memory management in effect in the OS which maps 
the real memory addresses into your address space. On 64 bit, a 
collision between stack and heap is practically impossible.

> I don't really understand why the system can't track the current top of the
> stack and bottom of the heap, and if they're going to collide, halt the
> process.

It does. But in a different way. For the heap, you need to call a 
function which asks for more memory. It returns an error code, if the 
memory can't be supplied. The problem is that often in this case, the 
program needs more memory to handle that, e.g. to format an error 
message. If you allocate memory in small pieces until it is exhausted, 
the program will die in unforeseen ways. If you try to alloc 1TB on the 
heap and it fails, there is enough room for a clean shutdown. Unless the 
C program is buggy and does not check the error.

On the stack, you don't allocate by telling the OS. You simply increase 
the stack pointer register. This is a single machine instruction, very 
fast, and unfeasible to trap by the OS and intercept. Instead, the stack 
is framed by pages which are non-writeable. As soon as the program tries 
to write there, it segfaults (SIGSEGV or SIGBUS). At this point there is 
no way to cleanly exit the program, therefore you see the 
crash/segfault. It might happen that you overrun the stack so much as to 
reach writeable memory again. But not under normal circumstances, where 
only a few bytes are pushed/popped.

> That would still be kinda awful, in a sudden "your application
> just died" kind of way, but it would be better than "your computer is now
> owned by some hacker in Hong Kong, who is now renting it by the hour to
> some spammer in Texas".

Stack overflow does not usually lead to security risks. A buffer 
overflow is different: It means that the program allocates a fixed-size 
buffer on the stack, which overflows and writes into the return 
addresses / local variables of functions higher up the callchain. The 
basic problem here is, that the C programmer was too lazy to get the 
memory from the heap.

	Christian



More information about the Python-list mailing list