[M3devel] Avoding thread-stack overflow, proof of concept of "leapfrog stacks"
Mika Nystrom
mika at async.caltech.edu
Wed Feb 23 17:42:06 CET 2011
Notes:
1. the Modula-3 garbage collector gets confused (shoulda thought of that),
so I have to turn it off
2. however if the GC were fixed, there's no need to "fix up" the stack
after the return---you can just allocate the new stacks as GC-traced:
even though the collector is compacting they are "pinned" because
they are referenced from the thread stack!
3. alloca is built into gcc nowadays, so I had to track down an assembly
version: I suspect that the compiler front-end could be modified to
emit a call to alloca and thus get gcc to generate the same code,
obviating the need for any assembly code at all.
(* Unsafe interface ***************************************************)
INTERFACE Unsafe;
FROM Ctypes IMPORT int;
PROCEDURE DoIt();
<*EXTERNAL alloca*>
PROCEDURE alloca(size : int) : INTEGER;
END Unsafe.
(* Unsafe implementation **********************************************)
UNSAFE MODULE Unsafe;
IMPORT Thread, IO, Fmt;
IMPORT RTCollector, Random;
EXCEPTION Quit;
VAR rand := NEW(Random.Default).init();
PROCEDURE P(cl : Closure; arg : ARRAY[0..100] OF INTEGER) RAISES { Quit } =
CONST Fudge = 1024;
VAR stack : REF ARRAY OF INTEGER := NIL;
BEGIN
IO.Put(Fmt.F("Thread %s GetSP()=0x%s\n",
Fmt.Int(cl.id),
Fmt.Int(GetSP(), base := 16))
);
(*Thread.Pause(0.1d0);*)
IF GetSP() < cl.lo + Fudge THEN
IF cl.stacks >= rand.integer(3,10) THEN
IO.Put(Fmt.F("Thread %s quitting after %s stacks\n",
Fmt.Int(cl.id), Fmt.Int(cl.stacks)));
RAISE Quit
END;
stack := NEW(REF ARRAY OF INTEGER, 8*1024);
WITH lo = LOOPHOLE(ADR(stack[0]),INTEGER),
hi = LOOPHOLE(ADR(stack[LAST(stack^)]),INTEGER),
sp = GetSP() DO
IO.Put(Fmt.F("Thread %s sp %s new stack lo %s hi %s\n",
Fmt.Int(cl.id),
Fmt.Int(sp, base := 16),
Fmt.Int(lo, base := 16),
Fmt.Int(hi, base:= 16)));
(* new stack starts sp - hi away *)
EVAL alloca(sp-hi);
IO.Put(Fmt.F("After alloca, sp %s\n",
Fmt.Int(GetSP(),base := 16)));
cl.lo := lo;
INC(cl.stacks)
END
END;
P(cl, arg)
END P;
TYPE
Closure = Thread.Closure OBJECT
id : CARDINAL;
lo : INTEGER;
stacks : CARDINAL;
OVERRIDES
apply := Apply
END;
PROCEDURE Apply(cl : Closure) : REFANY =
BEGIN
Thread.Pause(1.0d0);
LOOP
TRY
cl.lo := GetSP() - 1024*8; (* pretend we have 8k left *)
cl.stacks := 0;
P(cl, ARRAY [0..100] OF INTEGER { 0, .. });
EXCEPT
Quit => (* start over *)
END
END
END Apply;
PROCEDURE DoIt() =
BEGIN
RTCollector.Disable();
FOR i := 1 TO 2 DO
EVAL Thread.Fork(NEW(Closure, id := i))
END;
LOOP Thread.Pause(1.0d0) END
END DoIt;
PROCEDURE GetSP() : INTEGER = BEGIN RETURN alloca(1) END GetSP;
BEGIN END Unsafe.
(* Main can't be UNSAFE in Modula-3 ***********************************)
MODULE Main;
IMPORT Unsafe;
BEGIN Unsafe.DoIt() END Main.
(* alloca.s from FreeBSD (old code from BSD/386) **********************)
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
.asciz "@(#)alloca.s 5.2 (Berkeley) 5/14/90"
#include <machine/asm.h>
/* like alloc, but automatic automatic free in return */
.globl alloca
.type alloca, @function
alloca:
popl %edx /* pop return addr */
popl %eax /* pop amount to allocate */
movl %esp,%ecx
addl $3,%eax /* round up to next word */
andl $0xfffffffc,%eax
subl %eax,%esp
movl %esp,%eax /* base of newly allocated space */
pushl 8(%ecx) /* copy possible saved registers */
pushl 4(%ecx)
pushl 0(%ecx)
pushl %eax /* dummy to pop at callsite */
jmp *%edx /* "return" */
More information about the M3devel
mailing list