<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 10pt;
font-family:Tahoma
}
--></style>
</head>
<body class='hmmessage'>
Heap vs. stack is indeed an unsolvable dilemna.<BR>
Stack is much faster, but some arbitrary size must be chosen, that bothers me too, and detection and recovery from out of stack is tricky and not portable.<BR>
Heap is slow, but portable, and generally limited to address space (but subject to fragmentation), easy to detect exhaustion.<BR>
GC heap is usually fast to allocate, competitive with stack allocation, but the more you allocate, the more work for the GC to do.<BR>
There is no free lunch -- not even as cheap as it might seem. :)<BR>
 <BR>
Some systems..which I have never worked on..statically allocate everything.<BR>
They need to know they will never run out of memory.<BR>
 <BR>
> I realize my code is perhaps difficult to read.<BR>
 <BR>
Not necessarily. I didn't even try yet. :)<BR>
For many programmers, it is difficult to get them to read any code. :)<BR>
 <BR>
 <BR>
 - Jay<BR> <BR>
> To: jay.krell@cornell.edu<BR>> Date: Tue, 22 Feb 2011 10:45:02 -0800<BR>> From: mika@async.caltech.edu<BR>> CC: m3devel@elegosoft.com<BR>> Subject: Re: [M3devel] SEGV mapping to RuntimeError<BR>> <BR>> Jay K writes:<BR>> >--_ab466c75-f74a-4983-8fec-4f513f45fe0b_<BR>> >Content-Type: text/plain; charset="iso-8859-1"<BR>> >Content-Transfer-Encoding: quoted-printable<BR>> ><BR>> ><BR>> >(aside=2C and possible agreement: right -- an interpreter should consider N=<BR>> >OT recursing on the machine<BR>> >stack whenever code it is interpreting recurses=2C but definitely some do)<BR>> >=20<BR>> > - Jay<BR>> <BR>> <BR>> Jay, yes I agree---but:<BR>> <BR>> 1. of course it's easier to code the interpreter to recurse on the machine<BR>> stack<BR>> <BR>> 2. code called out from the interpreter will in any case recurse on the (a)<BR>> machine stack <BR>> <BR>> 3. again if one can "fix" the stack mechanism so that running out of<BR>> stack space is non-fatal, there's no reason not to use the machine stack<BR>> <BR>> I've found that Modula-3's garbage collector is brutally slow and that<BR>> converting code to using stack-allocated memory whenever possible is a<BR>> huge performance win under both PM3 and CM3. Perhaps this is a problem<BR>> with the garbage collector.<BR>> <BR>> I also have a partial design for a Scheme compiler (emitting Modula-3)<BR>> that would use the machine stack whenever possible rather than heap<BR>> allocation and do a "tricky thing" with local procedures to copy the<BR>> stack whenever a reference to the stack escapes. (Most of the time you<BR>> can implement Scheme on a stack but sometimes you need to keep part<BR>> of it live after you return; hence implementations (including mine)<BR>> heap-allocate local variables...)<BR>> <BR>> I realize my code is perhaps difficult to read. The gist of it is this:<BR>> when you run out of stack space, allocate a new stack anywhere else<BR>> in memory. Make it appear that you have alloca'd all the space between<BR>> the old and new stacks (into a variable that you of course never touch),<BR>> then continue. An issue is what to do when you return, you have to make<BR>> sure that you restore your old redzone.. perhaps you don't need to free<BR>> the stack eagerly: you could instead remember you have that page allocated<BR>> and re-use it next time you hit the redzone, or put it in a pool to allow<BR>> it to be used by another thread.<BR>> <BR>> The arbitrary choice of stack sizes has always bothered me greatly.<BR>> Some of my programs have thousands of threads and they use stack space<BR>> irregularly...<BR>> <BR>> Mika<BR>> <BR>> <BR>> >> To: rodney_bates@lcwb.coop<BR>> >> Date: Tue=2C 22 Feb 2011 09:44:05 -0800<BR>> >> From: mika@async.caltech.edu<BR>> >> CC: m3devel@elegosoft.com<BR>> >> Subject: Re: [M3devel] SEGV mapping to RuntimeError<BR>> >>=20<BR>> >>=20<BR>> >> Ok so I was thinking about this.<BR>> >>=20<BR>> >> Why on earth is stack overflow even a problem?<BR>> >>=20<BR>> >> Consider the following procedure call (in my code=2C stack grows upwards)=<BR>> >:<BR>> >>=20<BR>> >> (* sp at x=2C pc at y *)<BR>> >> y: P(args)<BR>> >> z: next_statement<BR>> >>=20<BR>> >> decompose as follows:<BR>> >>=20<BR>> >> (* sp at x=2C pc at y *)<BR>> >> y: Push(args etc. and ret. address z)<BR>> >> Jump(P)<BR>> >> z: next_statement<BR>> >>=20<BR>> >> Now=2C we say:<BR>> >>=20<BR>> >> y: ok :=3D check_stack(size of frame)<BR>> >> IF NOT ok THEN abort() END=3B<BR>> >> Push(args etc. and ret. address z)<BR>> >> Jump(P)<BR>> >> z: next_statement<BR>> >>=20<BR>> >> (note check_stack and the following IF can be implemented by hardware=2C<BR>> >> need not actually be an instruction)<BR>> >>=20<BR>> >> Let me change the code a tad:<BR>> >>=20<BR>> >> y: ok :=3D check_stack(size of frame)<BR>> >> y':IF NOT ok THEN=20<BR>> >> WITH new_stack_bottom =3D malloc(stack_size)<BR>> >> huge_amount =3D new_stack_bottom - sp DO<BR>> >> create_redzone_at(new_stack_bottom+stack_size-redzone_size)<BR>> >> EVAL alloca(huge_amount)=20<BR>> >> END<BR>> >> END=3B<BR>> >> Push(args etc. and ret. address z)<BR>> >> Jump(P)<BR>> >> z: IF NOT ok THEN destroy_redzone(...)=3B free(new_stack_bottom) END<BR>> >>=20<BR>> >> Note 1. cleanup of redzone could be postponed to return of caller....when<BR>> >> alloca in any case has to be cleaned up.<BR>> >>=20<BR>> >> Note 2. the test IF NOT ok at z is more expensive to implement than the<BR>> >> one at y because you can't really use hardware for it. A hardware callbac=<BR>> >k<BR>> >> can be arranged though:<BR>> >>=20<BR>> >> VAR ptr :=3D sp=3B<BR>> >> y: ok :=3D check_stack(size of frame)<BR>> >> y':IF NOT ok THEN=20<BR>> >> ptr :=3D 0=3B (* illegal address *)<BR>> >> fault_address :=3D z=3B<BR>> >> WITH new_stack_bottom =3D malloc(stack_size)<BR>> >> huge_amount =3D new_stack_bottom - sp DO<BR>> >> create_redzone_at(new_stack_bottom+stack_size-redzone_size)<BR>> >> EVAL alloca(huge_amount)=20<BR>> >> END<BR>> >> END=3B<BR>> >> Push(args etc. and ret. address z)<BR>> >> Jump(P)<BR>> >> z: EVAL ptr^ (* [ NOT ok -> hardware callback to SEGV: ] *)<BR>> >>=20<BR>> >> SEGV(signalpc): IF NOT ok AND signalpc =3D fault_address THEN destroy_red=<BR>> >zone(...)=3B free(new_stack_bottom) END<BR>> >>=20<BR>> >> Mika<BR>> >>=20<BR>> >>=20<BR>> >>=20<BR>> >>=20<BR>> >>=20<BR>> >> "Rodney M. Bates" writes:<BR>> >> ><BR>> >> ><BR>> >> >On 02/20/2011 12:37 PM=2C Mika Nystrom wrote:<BR>> >> >> On a 64-bit machine=2C at least=2C there ought to be enough virtual<BR>> >> >> memory that you could just have a gap between thread stacks big<BR>> >> >> enough to allow for a protection area larger than the largest possible<BR>> >> >> (implementation-defined) activation record=2C no? I know I've run into<BR>> >> >> trouble with very large activation records in the past (and not becaus=<BR>> >e<BR>> >> >> I was running out of stack space=2C either).<BR>> >> >><BR>> >> >> Or at least a procedure with a very large activation record (or<BR>> >> >> a procedure calling it) could be required to call some sort of check<BR>> >> >> routine "EnoughStackSpaceRemaining()" before starting to scribble<BR>> >> >> on the activation record?<BR>> >> ><BR>> >> >Hmm=2C I like this idea. It would introduce normal-case runtime overhead<BR>> >> >only for such procedures=2C and these are likely rare. Also=2C assuming =<BR>> >the procedure<BR>> >> >actually uses very much of its large AR=2C it should also have enough co=<BR>> >mputation<BR>> >> >time to wash out the stack check overhead.<BR>> >> ><BR>> >> >><BR>> >> >> Also the end of the activation record must be written to at least once=<BR>> >=2C<BR>> >> >> or else the memory protection won't be triggered.<BR>> >> >><BR>> >> ><BR>> >> >I was thinking (as an alternative mechanism) of having the compiler inte=<BR>> >ntionally<BR>> >> >add enough artificial write(s) as necessary to ensure storing within the<BR>> >> >red zone=2C and not just beyond it. This seems trickier to get right and<BR>> >> >harder to distinguish after the fact from a NIL dereference.<BR>> >> ><BR>> >> >> In any case if this is done properly the same mechanism I proposed for<BR>> >> >> SIGSEGV ought to be able to catch stack overflow=2C no? Well=2C as lon=<BR>> >g as<BR>> >> >> signals are delivered on a separate stack. If signals are delivered on<BR>> >> >> the same stack=2C the signal handler would get nastier=2C it would hav=<BR>> >e to<BR>> >> >> make space through some manipulations (maybe temporarily unporotecting<BR>> >> >> the redzone page?) for its own purposes... but I don't see why it<BR>> >> >> couldn't be done.<BR>> >> >><BR>> >> >> Not sure why I'm getting SIGILL... maybe I am getting my signal handle=<BR>> >r<BR>> >> >> activated inside the redzone page because of a difference in signal<BR>> >> >> handling..? I remember reading something about sigaltstack...<BR>> >> >><BR>> >> >> I would of course love to be able to recover from stack overflow=2C to=<BR>> >o.<BR>> >> >> In some sense=2C since it's a generally unknown limit=2C it's even les=<BR>> >s of<BR>> >> >> a fatal error than a NIL dereference (hence makes even more sense to<BR>> >> >> catch it).<BR>> >> ><BR>> >> >I think this would be a nice mechanism to have available. It would have =<BR>> >to<BR>> >> >be used with some care. In any case=2C it would be really nice and more<BR>> >> >frequently so=2C to at least have runtime error messages that distinguis=<BR>> >hed<BR>> >> >stack overflow from NIL deref.<BR>> >> ><BR>> >> >><BR>> >> >> Mika<BR>> >> >><BR>> >> >> "Rodney M. Bates" writes:<BR>> >> >>> I am pretty sure the cases I've seen are SIGSEGV on LINUXLIBC6 and AM=<BR>> >D64_LINUX.<BR>> >> >>> Probably a fully protected guard page at the end of the stack. This t=<BR>> >echnique<BR>> >> >>> always worries me a bit because a procedure with a really big activat=<BR>> >ion record<BR>> >> >>> could jump right past it. Probably it would almost always access the =<BR>> >first page<BR>> >> >>> of the big area before storing anything into later pages.<BR>> >> >>><BR>> >> >>> On 02/19/2011 05:27 PM=2C Mika Nystrom wrote:<BR>> >> >>>> Ah=2C yes=2C stack protection.<BR>> >> >>>><BR>> >> >>>> Do you know if it's a SIGSEGV=2C not a SIGBUS? I know I have seen SI=<BR>> >GILL on Macs.<BR>> >> >>>><BR>> >> >>>> Hmm=2C I get SIGILL on AMD64_FREEBSD as well:<BR>> >> >>>><BR>> >> >>>> time ../AMD64_FREEBSD/stubexample<BR>> >> >>>> M-Scheme Experimental<BR>> >> >>>> LITHP ITH LITHENING.<BR>> >> >>>>> (define (f a) (+ (f (+ a 1)) (f (+ a 2))))<BR>> >> >>>> f<BR>> >> >>>>> (f 0)<BR>> >> >>>> Illegal instruction<BR>> >> >>>> 3.847u 0.368s 0:13.32 31.5% 2160+284478k 0+0io 0pf+0w<BR>> >> >>>><BR>> >> >>>> What absolutely must not happen=2C of course=2C is that the runtime =<BR>> >hangs<BR>> >> >>>> while executing only safe code...<BR>> >> >>>><BR>> >> >>>> Mika<BR>> >> >>>><BR>> >> >>>> "Rodney M. Bates" writes:<BR>> >> >>>>> I know of one other place the compilers rely on hardware memory pro=<BR>> >tection<BR>> >> >>>>> to detect a checked runtime error=2C and that is stack overflow. Th=<BR>> >is won't<BR>> >> >>>>> corrupt anything=2C but is hard to distinguish from dereferencing N=<BR>> >IL.<BR>> >> >>>>> This could probably be distinguished after the fact by some low-lev=<BR>> >el=2C<BR>> >> >>>>> target-dependent code. I have found it by looking at assembly code =<BR>> >at<BR>> >> >>>>> the point of failure--usually right after a stack pointer push.<BR>> >> >>>>><BR>> >> >>>>> Detecting this via compiler-generated checks would probably be more<BR>> >> >>>>> extravagant than many other checks=2C as it is so frequent. I am no=<BR>> >t<BR>> >> >>>>> aware of any really good solution to this in any implementation of =<BR>> >any<BR>> >> >>>>> language.<BR>> >> >>>>><BR>> >> >>>>> On 02/19/2011 02:38 PM=2C Mika Nystrom wrote:<BR>> >> >>>>>> Jay=2C sometimes I wonder about you: this is a Modula-3 mailing li=<BR>> >st=2C<BR>> >> >>>>>> you know!<BR>> >> >>>>>><BR>> >> >>>>>> "Corrupting the heap" is something that can only happen as a resul=<BR>> >t of<BR>> >> >>>>>> an unchecked runtime error. Unchecked runtime errors cannot happen=<BR>> > in<BR>> >> >>>>>> modules not marked UNSAFE.<BR>> >> >>>>>><BR>> >> >>>>>> SEGV is=2C however=2C used by the CM3 implementation (and its pred=<BR>> >ecessors)<BR>> >> >>>>>> to signal a certain kind of *checked* runtime error=2C namely=2C t=<BR>> >he<BR>> >> >>>>>> dereferencing of a NIL reference. Correct me if I am wrong=2C but =<BR>> >an<BR>> >> >>>>>> attempt to dereference NIL is not going to leave the heap corrupte=<BR>> >d?<BR>> >> >>>>>><BR>> >> >>>>>> And if you stick to safe code=2C the only SEGVs I think you get in=<BR>> > the<BR>> >> >>>>>> current CM3 are ones from NIL dereferences.<BR>> >> >>>>>><BR>> >> >>>>>> Hence=2C as long as you stick with safe code=2C the only time the =<BR>> >code I<BR>> >> >>>>>> checked in earlier gets triggered is for NIL dereferences=2C which=<BR>> > should<BR>> >> >>>>>> never corrupt the heap. So SEGV is not sometimes=2C but in fact al=<BR>> >ways<BR>> >> >>>>>> recoverable.<BR>> >> >>>>>><BR>> >> >>>>>> :-)<BR>> >> >>>>>><BR>> >> >>>>>> Mika<BR>> >> >>>>>><BR>> >> >>>>>> P.S. the bit above "if you stick to safe code": if you actually pr=<BR>> >ogram in<BR>> >> >>>>>> Modula-3 you almost never use UNSAFE. I went through my repository=<BR>> > and<BR>> >> >>>>>> I have 40 modules using UNSAFE out of a total of 4=2C559. Furtherm=<BR>> >ore=2C<BR>> >> >>>>>> many of the UNSAFE modules are glue code to Fortran routines=2C wh=<BR>> >ich<BR>> >> >>>>>> could relatively easily be verified to be safe in the Modula-3 sen=<BR>> >se.<BR>> >> >>>>>> Almost all what remains is glue to some C library=2C which wouldn'=<BR>> >t be<BR>> >> >>>>>> necessary if the rest of the world would wake up out of the dark a=<BR>> >ges=2C but<BR>> >> >>>>>> I don't have the time to rewrite every single library from scratch=<BR>> > myself.<BR>> >> >>>>>><BR>> >> >>>>>><BR>> >> >>>>>> Jay K writes:<BR>> >> >>>>>>> --_a2a24b92-3b4c-456e-ab1b-c3f5e912854f_<BR>> >> >>>>>>> Content-Type: text/plain=3B charset=3D"iso-8859-1"<BR>> >> >>>>>>> Content-Transfer-Encoding: quoted-printable<BR>> >> >>>>>>><BR>> >> >>>>>>><BR>> >> >>>>>>> Letting any code run after a SIGSEGV is dubious.<BR>> >> >>>>>>> Imagine the heap is corrupted.<BR>> >> >>>>>>> And then you run more code.<BR>> >> >>>>>>> And the code happens to call malloc.<BR>> >> >>>>>>> Or printf to log something.<BR>> >> >>>>>>> =3D20<BR>> >> >>>>>>> I suppose there might be an application that maps memory<BR>> >> >>>>>>> gradually=3D2C as pieces of a buffer are hit. Might.<BR>> >> >>>>>>> =3D20<BR>> >> >>>>>>> - Jay<BR>> >> >>>>>>> =3D20<BR>> >> >>>>>>>> To: m3devel@elegosoft.com<BR>> >> >>>>>>>> Date: Sat=3D2C 19 Feb 2011 10:29:30 -0800<BR>> >> >>>>>>>> From: mika@async.caltech.edu<BR>> >> >>>>>>>> Subject: [M3devel] SEGV mapping to RuntimeError<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> Dear m3devel=3D2C<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> For a while it has annoyed me that segmentation violations cause=<BR>> > an<BR>> >> >>>>>>>> unconditional program abort. I've changed that now so that (unde=<BR>> >r user<BR>> >> >>>>>>>> threads at least) we instead get a RuntimeError. Here's an examp=<BR>> >le of<BR>> >> >>>>>>>> the mechanism at work in an interactive Scheme environment. Cons=<BR>> >ider<BR>> >> >>>>>>>> the unhelpful interface and module Crash:<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> INTERFACE Crash=3D3B PROCEDURE Me()=3D3B END Crash.<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> MODULE Crash=3D3B<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> PROCEDURE Me() =3D3D<BR>> >> >>>>>>>> VAR ptr : REF INTEGER :=3D3D NIL=3D3B BEGIN<BR>> >> >>>>>>>> ptr^ :=3D3D 0<BR>> >> >>>>>>>> END Me=3D3B<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> BEGIN END Crash.<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> Here's an example of what happens if you now call this from an i=<BR>> >nteractiv=3D<BR>> >> >>>>>>> e<BR>> >> >>>>>>>> interpreter that catches the exception RuntimeError.E:<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> M-Scheme Experimental<BR>> >> >>>>>>>> LITHP ITH LITHENING.<BR>> >> >>>>>>>>> (require-modules "m3")<BR>> >> >>>>>>>> #t<BR>> >> >>>>>>>>> (Crash.Me)<BR>> >> >>>>>>>> EXCEPTION! RuntimeError! Attempt to reference an illegal memory =<BR>> >location.<BR>> >> >>>>>>>>> (+ 3 4)=3D20<BR>> >> >>>>>>>> 7<BR>> >> >>>>>>>>> =3D20<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> I just realized I may have broken pthreads=3D2C let me go back a=<BR>> >nd double-c=3D<BR>> >> >>>>>>> heck it.=3D20<BR>> >> >>>>>>>> runtime/POSIX and thread/POSIX don't refer to the same thing do =<BR>> >they...<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>>> Mika<BR>> >> >>>>>>>> =3D20<BR>> >> >>>>>>> =3D<BR>> >> >>>>>>><BR>> >> >>>>>>> --_a2a24b92-3b4c-456e-ab1b-c3f5e912854f_<BR>> >> >>>>>>> Content-Type: text/html=3B charset=3D"iso-8859-1"<BR>> >> >>>>>>> Content-Transfer-Encoding: quoted-printable<BR>> >> >>>>>>><BR>> >> >>>>>>> <html><BR>> >> >>>>>>> <head><BR>> >> >>>>>>> <style><!--<BR>> >> >>>>>>> .hmmessage P<BR>> >> >>>>>>> {<BR>> >> >>>>>>> margin:0px=3D3B<BR>> >> >>>>>>> padding:0px<BR>> >> >>>>>>> }<BR>> >> >>>>>>> body.hmmessage<BR>> >> >>>>>>> {<BR>> >> >>>>>>> font-size: 10pt=3D3B<BR>> >> >>>>>>> font-family:Tahoma<BR>> >> >>>>>>> }<BR>> >> >>>>>>> --></style><BR>> >> >>>>>>> </head><BR>> >> >>>>>>> <body class=3D3D'hmmessage'><BR>> >> >>>>>>> Letting any code run after a SIGSEGV is dubious.<BR><BR>> >> >>>>>>> Imagine the heap&nbsp=3D3Bis corrupted.<BR><BR>> >> >>>>>>> And then you run more code.<BR><BR>> >> >>>>>>> And the code happens to call malloc.<BR><BR>> >> >>>>>>> Or printf to log something.<BR><BR>> >> >>>>>>> &nbsp=3D3B<BR><BR>> >> >>>>>>> I suppose there might be an application that maps memory<BR><BR>> >> >>>>>>> gradually=3D2C as pieces of a buffer are hit. Might.<BR><BR>> >> >>>>>>> &nbsp=3D3B<BR><BR>> >> >>>>>>> &nbsp=3D3B- Jay<BR>&nbsp=3D3B<BR><BR>> >> >>>>>>> &gt=3D3B To: m3devel@elegosoft.com<BR>&gt=3D3B Date: Sat=3D2C 19 =<BR>> >Feb 2011 10:29:3=3D<BR>> >> >>>>>>> 0 -0800<BR>&gt=3D3B From: mika@async.caltech.edu<BR>&gt=3D3B Subj=<BR>> >ect: [M3devel]=3D<BR>> >> >>>>>>> SEGV mapping to RuntimeError<BR>&gt=3D3B<BR>&gt=3D3B<BR>&gt=3D3B =<BR>> >Dear m3devel=3D<BR>> >> >>>>>>> =3D2C<BR>&gt=3D3B<BR>&gt=3D3B For a while it has annoyed me that =<BR>> >segmentation vi=3D<BR>> >> >>>>>>> olations cause an<BR>&gt=3D3B unconditional program abort. I've c=<BR>> >hanged that =3D<BR>> >> >>>>>>> now so that (under user<BR>&gt=3D3B threads at least) we instead =<BR>> >get a Runtim=3D<BR>> >> >>>>>>> eError. Here's an example of<BR>&gt=3D3B the mechanism at work in=<BR>> > an interact=3D<BR>> >> >>>>>>> ive Scheme environment. Consider<BR>&gt=3D3B the unhelpful interf=<BR>> >ace and modu=3D<BR>> >> >>>>>>> le Crash:<BR>&gt=3D3B<BR>&gt=3D3B INTERFACE Crash=3D3B PROCEDURE =<BR>> >Me()=3D3B END Cra=3D<BR>> >> >>>>>>> sh.<BR>&gt=3D3B<BR>&gt=3D3B MODULE Crash=3D3B<BR>&gt=3D3B<BR>&gt=<BR>> >=3D3B PROCEDURE Me(=3D<BR>> >> >>>>>>> ) =3D3D<BR>&gt=3D3B VAR ptr : REF INTEGER :=3D3D NIL=3D3B BEGIN<B=<BR>> >R>&gt=3D3B ptr^ :=3D3D=3D<BR>> >> >>>>>>> 0<BR>&gt=3D3B END Me=3D3B<BR>&gt=3D3B<BR>&gt=3D3B BEGIN END Crash=<BR>> >.<BR>&gt=3D3B<BR>=3D<BR>> >> >>>>>>> &gt=3D3B Here's an example of what happens if you now call this f=<BR>> >rom an inter=3D<BR>> >> >>>>>>> active<BR>&gt=3D3B interpreter that catches the exception Runtime=<BR>> >Error.E:<BR>=3D<BR>> >> >>>>>>> &gt=3D3B<BR>&gt=3D3B M-Scheme Experimental<BR>&gt=3D3B LITHP ITH =<BR>> >LITHENING.<BR>&=3D<BR>> >> >>>>>>> gt=3D3B&gt=3D3B (require-modules "m3")<BR>&gt=3D3B #t<BR>&gt=3D3B=<BR>> >&gt=3D3B (Crash.Me=3D<BR>> >> >>>>>>> )<BR>&gt=3D3B EXCEPTION! RuntimeError! Attempt to reference an il=<BR>> >legal memory=3D<BR>> >> >>>>>>> location.<BR>&gt=3D3B&gt=3D3B (+ 3 4)<BR>&gt=3D3B 7<BR>&gt=3D3B&g=<BR>> >t=3D3B<BR>&gt=3D<BR>> >> >>>>>>> =3D3B<BR>&gt=3D3B I just realized I may have broken pthreads=3D2C=<BR>> > let me go back=3D<BR>> >> >>>>>>> and double-check it.<BR>&gt=3D3B runtime/POSIX and thread/POSIX d=<BR>> >on't refer=3D<BR>> >> >>>>>>> to the same thing do they...<BR>&gt=3D3B<BR>&gt=3D3B Mika<BR>&gt=<BR>> >=3D3B<BR> =3D<BR>> >> >>>>>>> </body><BR>> >> >>>>>>> </html>=3D<BR>> >> >>>>>>><BR>> >> >>>>>>> --_a2a24b92-3b4c-456e-ab1b-c3f5e912854f_--<BR>> >> >>>>>><BR>> >> >>>><BR>> >> >><BR>> > =<BR>> ><BR>> >--_ab466c75-f74a-4983-8fec-4f513f45fe0b_<BR>> >Content-Type: text/html; charset="iso-8859-1"<BR>> >Content-Transfer-Encoding: quoted-printable<BR>> ><BR>> ><html><BR>> ><head><BR>> ><style><!--<BR>> >.hmmessage P<BR>> >{<BR>> >margin:0px=3B<BR>> >padding:0px<BR>> >}<BR>> >body.hmmessage<BR>> >{<BR>> >font-size: 10pt=3B<BR>> >font-family:Tahoma<BR>> >}<BR>> >--></style><BR>> ></head><BR>> ><body class=3D'hmmessage'><BR>> >(aside=2C and possible agreement: right -- an interpreter should consider N=<BR>> >OT recursing on the machine<BR><BR>> >stack whenever code it is interpreting recurses=2C but definitely some do)<=<BR>> >BR><BR>> >&nbsp=3B<BR><BR>> >&nbsp=3B- Jay<BR>&nbsp=3B<BR><BR>> >&gt=3B To: rodney_bates@lcwb.coop<BR>&gt=3B Date: Tue=2C 22 Feb 2011 09:44:=<BR>> >05 -0800<BR>&gt=3B From: mika@async.caltech.edu<BR>&gt=3B CC: m3devel@elego=<BR>> >soft.com<BR>&gt=3B Subject: Re: [M3devel] SEGV mapping to RuntimeError<BR>&=<BR>> >gt=3B <BR>&gt=3B <BR>&gt=3B Ok so I was thinking about this.<BR>&gt=3B <BR>=<BR>> >&gt=3B Why on earth is stack overflow even a problem?<BR>&gt=3B <BR>&gt=3B =<BR>> >Consider the following procedure call (in my code=2C stack grows upwards):<=<BR>> >BR>&gt=3B <BR>&gt=3B (* sp at x=2C pc at y *)<BR>&gt=3B y: P(args)<BR>&gt=<BR>> >=3B z: next_statement<BR>&gt=3B <BR>&gt=3B decompose as follows:<BR>&gt=3B =<BR>> ><BR>&gt=3B (* sp at x=2C pc at y *)<BR>&gt=3B y: Push(args etc. and ret. ad=<BR>> >dress z)<BR>&gt=3B Jump(P)<BR>&gt=3B z: next_statement<BR>&gt=3B <BR>&gt=3B=<BR>> > Now=2C we say:<BR>&gt=3B <BR>&gt=3B y: ok :=3D check_stack(size of frame)<=<BR>> >BR>&gt=3B IF NOT ok THEN abort() END=3B<BR>&gt=3B Push(args etc. and ret. a=<BR>> >ddress z)<BR>&gt=3B Jump(P)<BR>&gt=3B z: next_statement<BR>&gt=3B <BR>&gt=<BR>> >=3B (note check_stack and the following IF can be implemented by hardware=<BR>> >=2C<BR>&gt=3B need not actually be an instruction)<BR>&gt=3B <BR>&gt=3B Let=<BR>> > me change the code a tad:<BR>&gt=3B <BR>&gt=3B y: ok :=3D check_stack(size=<BR>> > of frame)<BR>&gt=3B y':IF NOT ok THEN <BR>&gt=3B WITH new_stack_bottom =3D=<BR>> > malloc(stack_size)<BR>&gt=3B huge_amount =3D new_stack_bottom - sp DO<BR>&=<BR>> >gt=3B create_redzone_at(new_stack_bottom+stack_size-redzone_size)<BR>&gt=3B=<BR>> > EVAL alloca(huge_amount) <BR>&gt=3B END<BR>&gt=3B END=3B<BR>&gt=3B Push(ar=<BR>> >gs etc. and ret. address z)<BR>&gt=3B Jump(P)<BR>&gt=3B z: IF NOT ok THEN d=<BR>> >estroy_redzone(...)=3B free(new_stack_bottom) END<BR>&gt=3B <BR>&gt=3B Note=<BR>> > 1. cleanup of redzone could be postponed to return of caller....when<BR>&g=<BR>> >t=3B alloca in any case has to be cleaned up.<BR>&gt=3B <BR>&gt=3B Note 2. =<BR>> >the test IF NOT ok at z is more expensive to implement than the<BR>&gt=3B o=<BR>> >ne at y because you can't really use hardware for it. A hardware callback<B=<BR>> >R>&gt=3B can be arranged though:<BR>&gt=3B <BR>&gt=3B VAR ptr :=3D sp=3B<BR=<BR>> >>&gt=3B y: ok :=3D check_stack(size of frame)<BR>&gt=3B y':IF NOT ok THEN <=<BR>> >BR>&gt=3B ptr :=3D 0=3B (* illegal address *)<BR>&gt=3B fault_address :=3D =<BR>> >z=3B<BR>&gt=3B WITH new_stack_bottom =3D malloc(stack_size)<BR>&gt=3B huge_=<BR>> >amount =3D new_stack_bottom - sp DO<BR>&gt=3B create_redzone_at(new_stack_b=<BR>> >ottom+stack_size-redzone_size)<BR>&gt=3B EVAL alloca(huge_amount) <BR>&gt=<BR>> >=3B END<BR>&gt=3B END=3B<BR>&gt=3B Push(args etc. and ret. address z)<BR>&g=<BR>> >t=3B Jump(P)<BR>&gt=3B z: EVAL ptr^ (* [ NOT ok -&gt=3B hardware callback t=<BR>> >o SEGV: ] *)<BR>&gt=3B <BR>&gt=3B SEGV(signalpc): IF NOT ok AND signalpc =<BR>> >=3D fault_address THEN destroy_redzone(...)=3B free(new_stack_bottom) END<B=<BR>> >R>&gt=3B <BR>&gt=3B Mika<BR>&gt=3B <BR>&gt=3B <BR>&gt=3B <BR>&gt=3B <BR>&gt=<BR>> >=3B <BR>&gt=3B "Rodney M. Bates" writes:<BR>&gt=3B &gt=3B<BR>&gt=3B &gt=3B<=<BR>> >BR>&gt=3B &gt=3BOn 02/20/2011 12:37 PM=2C Mika Nystrom wrote:<BR>&gt=3B &gt=<BR>> >=3B&gt=3B On a 64-bit machine=2C at least=2C there ought to be enough virtu=<BR>> >al<BR>&gt=3B &gt=3B&gt=3B memory that you could just have a gap between thr=<BR>> >ead stacks big<BR>&gt=3B &gt=3B&gt=3B enough to allow for a protection area=<BR>> > larger than the largest possible<BR>&gt=3B &gt=3B&gt=3B (implementation-de=<BR>> >fined) activation record=2C no? I know I've run into<BR>&gt=3B &gt=3B&gt=3B=<BR>> > trouble with very large activation records in the past (and not because<BR=<BR>> >>&gt=3B &gt=3B&gt=3B I was running out of stack space=2C either).<BR>&gt=3B=<BR>> > &gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B Or at least a procedure with a very la=<BR>> >rge activation record (or<BR>&gt=3B &gt=3B&gt=3B a procedure calling it) co=<BR>> >uld be required to call some sort of check<BR>&gt=3B &gt=3B&gt=3B routine "=<BR>> >EnoughStackSpaceRemaining()" before starting to scribble<BR>&gt=3B &gt=3B&g=<BR>> >t=3B on the activation record?<BR>&gt=3B &gt=3B<BR>&gt=3B &gt=3BHmm=2C I li=<BR>> >ke this idea. It would introduce normal-case runtime overhead<BR>&gt=3B &gt=<BR>> >=3Bonly for such procedures=2C and these are likely rare. Also=2C assuming =<BR>> >the procedure<BR>&gt=3B &gt=3Bactually uses very much of its large AR=2C it=<BR>> > should also have enough computation<BR>&gt=3B &gt=3Btime to wash out the s=<BR>> >tack check overhead.<BR>&gt=3B &gt=3B<BR>&gt=3B &gt=3B&gt=3B<BR>&gt=3B &gt=<BR>> >=3B&gt=3B Also the end of the activation record must be written to at least=<BR>> > once=2C<BR>&gt=3B &gt=3B&gt=3B or else the memory protection won't be trig=<BR>> >gered.<BR>&gt=3B &gt=3B&gt=3B<BR>&gt=3B &gt=3B<BR>&gt=3B &gt=3BI was thinki=<BR>> >ng (as an alternative mechanism) of having the compiler intentionally<BR>&g=<BR>> >t=3B &gt=3Badd enough artificial write(s) as necessary to ensure storing wi=<BR>> >thin the<BR>&gt=3B &gt=3Bred zone=2C and not just beyond it. This seems tri=<BR>> >ckier to get right and<BR>&gt=3B &gt=3Bharder to distinguish after the fact=<BR>> > from a NIL dereference.<BR>&gt=3B &gt=3B<BR>&gt=3B &gt=3B&gt=3B In any cas=<BR>> >e if this is done properly the same mechanism I proposed for<BR>&gt=3B &gt=<BR>> >=3B&gt=3B SIGSEGV ought to be able to catch stack overflow=2C no? Well=2C a=<BR>> >s long as<BR>&gt=3B &gt=3B&gt=3B signals are delivered on a separate stack.=<BR>> > If signals are delivered on<BR>&gt=3B &gt=3B&gt=3B the same stack=2C the s=<BR>> >ignal handler would get nastier=2C it would have to<BR>&gt=3B &gt=3B&gt=3B =<BR>> >make space through some manipulations (maybe temporarily unporotecting<BR>&=<BR>> >gt=3B &gt=3B&gt=3B the redzone page?) for its own purposes... but I don't s=<BR>> >ee why it<BR>&gt=3B &gt=3B&gt=3B couldn't be done.<BR>&gt=3B &gt=3B&gt=3B<B=<BR>> >R>&gt=3B &gt=3B&gt=3B Not sure why I'm getting SIGILL... maybe I am getting=<BR>> > my signal handler<BR>&gt=3B &gt=3B&gt=3B activated inside the redzone page=<BR>> > because of a difference in signal<BR>&gt=3B &gt=3B&gt=3B handling..? I rem=<BR>> >ember reading something about sigaltstack...<BR>&gt=3B &gt=3B&gt=3B<BR>&gt=<BR>> >=3B &gt=3B&gt=3B I would of course love to be able to recover from stack ov=<BR>> >erflow=2C too.<BR>&gt=3B &gt=3B&gt=3B In some sense=2C since it's a general=<BR>> >ly unknown limit=2C it's even less of<BR>&gt=3B &gt=3B&gt=3B a fatal error =<BR>> >than a NIL dereference (hence makes even more sense to<BR>&gt=3B &gt=3B&gt=<BR>> >=3B catch it).<BR>&gt=3B &gt=3B<BR>&gt=3B &gt=3BI think this would be a nic=<BR>> >e mechanism to have available. It would have to<BR>&gt=3B &gt=3Bbe used wit=<BR>> >h some care. In any case=2C it would be really nice and more<BR>&gt=3B &gt=<BR>> >=3Bfrequently so=2C to at least have runtime error messages that distinguis=<BR>> >hed<BR>&gt=3B &gt=3Bstack overflow from NIL deref.<BR>&gt=3B &gt=3B<BR>&gt=<BR>> >=3B &gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B Mika<BR>&gt=3B &gt=3B&gt=3B<BR>&gt=<BR>> >=3B &gt=3B&gt=3B "Rodney M. Bates" writes:<BR>&gt=3B &gt=3B&gt=3B&gt=3B I a=<BR>> >m pretty sure the cases I've seen are SIGSEGV on LINUXLIBC6 and AMD64_LINUX=<BR>> >.<BR>&gt=3B &gt=3B&gt=3B&gt=3B Probably a fully protected guard page at the=<BR>> > end of the stack. This technique<BR>&gt=3B &gt=3B&gt=3B&gt=3B always worri=<BR>> >es me a bit because a procedure with a really big activation record<BR>&gt=<BR>> >=3B &gt=3B&gt=3B&gt=3B could jump right past it. Probably it would almost a=<BR>> >lways access the first page<BR>&gt=3B &gt=3B&gt=3B&gt=3B of the big area be=<BR>> >fore storing anything into later pages.<BR>&gt=3B &gt=3B&gt=3B&gt=3B<BR>&gt=<BR>> >=3B &gt=3B&gt=3B&gt=3B On 02/19/2011 05:27 PM=2C Mika Nystrom wrote:<BR>&gt=<BR>> >=3B &gt=3B&gt=3B&gt=3B&gt=3B Ah=2C yes=2C stack protection.<BR>&gt=3B &gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B Do you know if it'=<BR>> >s a SIGSEGV=2C not a SIGBUS? I know I have seen SIGILL on Macs.<BR>&gt=3B &=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B Hmm=2C I get SIG=<BR>> >ILL on AMD64_FREEBSD as well:<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B =<BR>> >&gt=3B&gt=3B&gt=3B&gt=3B time ../AMD64_FREEBSD/stubexample<BR>&gt=3B &gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B M-Scheme Experimental<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B=<BR>> > LITHP ITH LITHENING.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B (define (f a=<BR>> >) (+ (f (+ a 1)) (f (+ a 2))))<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B f<BR>&gt=<BR>> >=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B (f 0)<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B=<BR>> > Illegal instruction<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B 3.847u 0.368s 0:13.=<BR>> >32 31.5% 2160+284478k 0+0io 0pf+0w<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B<BR>&g=<BR>> >t=3B &gt=3B&gt=3B&gt=3B&gt=3B What absolutely must not happen=2C of course=<BR>> >=2C is that the runtime hangs<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B while exec=<BR>> >uting only safe code...<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B Mika<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B "Rodney M. Bates" writes:<BR>&gt=3B &gt=3B&gt=3B&gt=3B&g=<BR>> >t=3B&gt=3B I know of one other place the compilers rely on hardware memory =<BR>> >protection<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B to detect a checked run=<BR>> >time error=2C and that is stack overflow. This won't<BR>&gt=3B &gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B corrupt anything=2C but is hard to distinguish from dere=<BR>> >ferencing NIL.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B This could probably=<BR>> > be distinguished after the fact by some low-level=2C<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B target-dependent code. I have found it by looking at =<BR>> >assembly code at<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B the point of fail=<BR>> >ure--usually right after a stack pointer push.<BR>&gt=3B &gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Detecting this via co=<BR>> >mpiler-generated checks would probably be more<BR>&gt=3B &gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B extravagant than many other checks=2C as it is so frequent. I =<BR>> >am not<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B aware of any really good so=<BR>> >lution to this in any implementation of any<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B language.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B On 02/19/2011 02:38 PM=2C Mika Nystrom wrote:<B=<BR>> >R>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Jay=2C sometimes I wonder abo=<BR>> >ut you: this is a Modula-3 mailing list=2C<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B you know!<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR=<BR>> >>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B "Corrupting the heap" is somet=<BR>> hing that can only happen as a result of<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B an unchecked runtime error. Unchecked runtime errors cannot ha=<BR>> >ppen in<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B modules not marked U=<BR>> >NSAFE.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B SEGV is=2C however=2C used by the CM3 implement=<BR>> >ation (and its predecessors)<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> > to signal a certain kind of *checked* runtime error=2C namely=2C the<BR>&g=<BR>> >t=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B dereferencing of a NIL reference.=<BR>> > Correct me if I am wrong=2C but an<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B attempt to dereference NIL is not going to leave the heap corrupt=<BR>> >ed?<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B And if you stick to safe code=2C the only SEGVs I th=<BR>> >ink you get in the<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B current C=<BR>> >M3 are ones from NIL dereferences.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Hence=2C as long as y=<BR>> >ou stick with safe code=2C the only time the code I<BR>&gt=3B &gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B checked in earlier gets triggered is for NIL derefe=<BR>> >rences=2C which should<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B never=<BR>> > corrupt the heap. So SEGV is not sometimes=2C but in fact always<BR>&gt=3B=<BR>> > &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B recoverable.<BR>&gt=3B &gt=3B&gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B :-)<B=<BR>> >R>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B Mika<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&g=<BR>> >t=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B P.S. the bit above "if you stick =<BR>> >to safe code": if you actually program in<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B Modula-3 you almost never use UNSAFE. I went through my rep=<BR>> >ository and<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B I have 40 module=<BR>> >s using UNSAFE out of a total of 4=2C559. Furthermore=2C<BR>&gt=3B &gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B&gt=3B many of the UNSAFE modules are glue code to Fo=<BR>> >rtran routines=2C which<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B coul=<BR>> >d relatively easily be verified to be safe in the Modula-3 sense.<BR>&gt=3B=<BR>> > &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Almost all what remains is glue to so=<BR>> >me C library=2C which wouldn't be<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B necessary if the rest of the world would wake up out of the dark ages=<BR>> >=2C but<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B I don't have the tim=<BR>> >e to rewrite every single library from scratch myself.<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<=<BR>> >BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Jay K writes:<BR>&gt=3B &gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B --_a2a24b92-3b4c-456e-ab1b-c3f5e912=<BR>> >854f_<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Content-Type: te=<BR>> >xt/plain=3B charset=3D"iso-8859-1"<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B Content-Transfer-Encoding: quoted-printable<BR>&gt=3B &gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Letting a=<BR>> >ny code run after a SIGSEGV is dubious.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B Imagine the heap is corrupted.<BR>&gt=3B &gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B And then you run more code.<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B And the code happens to call malloc.<BR>&=<BR>> >gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Or printf to log something=<BR>> >.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B I suppose there might be an applica=<BR>> >tion that maps memory<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =<BR>> >gradually=3D2C as pieces of a buffer are hit. Might.<BR>&gt=3B &gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B - Jay<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =<BR>> >=3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B To: m3deve=<BR>> >l@elegosoft.com<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =<BR>> >Date: Sat=3D2C 19 Feb 2011 10:29:30 -0800<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B From: mika@async.caltech.edu<BR>&gt=3B &gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Subject: [M3devel] SEGV mapping to=<BR>> > RuntimeError<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =<BR>> >=3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&=<BR>> >gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Dear m3devel=3D2C<BR=<BR>> >>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B For a while it has annoyed m=<BR>> >e that segmentation violations cause an<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B unconditional program abort. I've changed that now =<BR>> >so that (under user<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B threads at least) we instead get a RuntimeError. Here's an example of<B=<BR>> >R>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B the mechanism at =<BR>> >work in an interactive Scheme environment. Consider<BR>&gt=3B &gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B the unhelpful interface and module Cras=<BR>> >h:<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&gt=<BR>> >=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B INTERFACE Crash=3D3B P=<BR>> >ROCEDURE Me()=3D3B END Crash.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B MODULE Crash=3D3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =<BR>> >PROCEDURE Me() =3D3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&g=<BR>> >t=3B VAR ptr : REF INTEGER :=3D3D NIL=3D3B BEGIN<BR>&gt=3B &gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B ptr^ :=3D3D 0<BR>&gt=3B &gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B END Me=3D3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B BEGIN END Crash.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B Here's an example of what happens if you now call this from an=<BR>> > interactiv=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B e<BR>&g=<BR>> >t=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B interpreter that catc=<BR>> >hes the exception RuntimeError.E:<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B M-Scheme Experimental<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B LITHP ITH LITHENING.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B (require-modules "m3")<BR>&gt=3B &gt=3B&gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B #t<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B (Crash.Me)<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B EXCEPTION! RuntimeError! Attempt to reference an ill=<BR>> >egal memory location.<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B (+ 3 4)=3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B 7<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D20<=<BR>> >BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B I just realized =<BR>> >I may have broken pthreads=3D2C let me go back and double-c=3D<BR>&gt=3B &g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B heck it.=3D20<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B runtime/POSIX and thread/POSIX don'=<BR>> >t refer to the same thing do they...<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B Mika<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> > =3D20<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D<BR>&gt=3B &=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B --_a2a24b92-3b4c-456e-ab1b-c3f5e912854f_<BR>&gt=3B &g=<BR>> >t=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Content-Type: text/html=3B charset=<BR>> >=3D"iso-8859-1"<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Conten=<BR>> >t-Transfer-Encoding: quoted-printable<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &lt=3B=<BR>> >html&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &lt=3Bhead&=<BR>> >gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &lt=3Bstyle&gt=<BR>> >=3B&lt=3B!--<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B .hmmessag=<BR>> >e P<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B {<BR>&gt=3B &gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B margin:0px=3D3B<BR>&gt=3B &gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B padding:0px<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B }<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B body.hmmessage<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B {<B=<BR>> >R>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B font-size: 10pt=3D3B<BR=<BR>> >>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B font-family:Tahoma<BR>&g=<BR>> >t=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B }<BR>&gt=3B &gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B --&gt=3B&lt=3B/style&gt=3B<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &lt=3B/head&gt=3B<BR>&gt=3B &gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &lt=3Bbody class=3D3D'hmmessage'&gt=3B<BR>&gt=<BR>> >=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B Letting any code run after a=<BR>> > SIGSEGV is dubious.&lt=3BBR&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B Imagine the heap&amp=3Bnbsp=3D3Bis corrupted.&lt=3BBR&gt=3B<BR=<BR>> >>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B And then you run more co=<BR>> >de.&lt=3BBR&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B And =<BR>> >the code happens to call malloc.&lt=3BBR&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B&gt=3B Or printf to log something.&lt=3BBR&gt=3B<BR>&gt=<BR>> >=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &amp=3Bnbsp=3D3B&lt=3BBR&gt=<BR>> >=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B I suppose there mi=<BR>> >ght be an application that maps memory&lt=3BBR&gt=3B<BR>&gt=3B &gt=3B&gt=3B=<BR>> >&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B gradually=3D2C as pieces of a buffer are hit=<BR>> >. Might.&lt=3BBR&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B=<BR>> > &amp=3Bnbsp=3D3B&lt=3BBR&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B &amp=3Bnbsp=3D3B- Jay&lt=3BBR&gt=3B&amp=3Bnbsp=3D3B&lt=3BBR&gt=3B=<BR>> ><BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &amp=3Bgt=3D3B To: m3=<BR>> >devel@elegosoft.com&lt=3BBR&gt=3B&amp=3Bgt=3D3B Date: Sat=3D2C 19 Feb 2011 =<BR>> >10:29:3=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B 0 -0800&lt=<BR>> >=3BBR&gt=3B&amp=3Bgt=3D3B From: mika@async.caltech.edu&lt=3BBR&gt=3B&amp=3B=<BR>> >gt=3D3B Subject: [M3devel]=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B SEGV mapping to RuntimeError&lt=3BBR&gt=3B&amp=3Bgt=3D3B&lt=3BBR&=<BR>> >gt=3B&amp=3Bgt=3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B Dear m3devel=3D<BR>&gt=3B &=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D2C&lt=3BBR&gt=3B&amp=3Bgt=3D3B=<BR>> >&lt=3BBR&gt=3B&amp=3Bgt=3D3B For a while it has annoyed me that segmentatio=<BR>> >n vi=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B olations cause=<BR>> > an&lt=3BBR&gt=3B&amp=3Bgt=3D3B unconditional program abort. I've changed t=<BR>> >hat =3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B now so that (u=<BR>> >nder user&lt=3BBR&gt=3B&amp=3Bgt=3D3B threads at least) we instead get a Ru=<BR>> >ntim=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B eError. Here's=<BR>> > an example of&lt=3BBR&gt=3B&amp=3Bgt=3D3B the mechanism at work in an inte=<BR>> >ract=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B ive Scheme env=<BR>> >ironment. Consider&lt=3BBR&gt=3B&amp=3Bgt=3D3B the unhelpful interface and =<BR>> >modu=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B le Crash:&lt=<BR>> >=3BBR&gt=3B&amp=3Bgt=3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B INTERFACE Crash=3D3B =<BR>> >PROCEDURE Me()=3D3B END Cra=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B sh.&lt=3BBR&gt=3B&amp=3Bgt=3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B MODUL=<BR>> >E Crash=3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B PROCED=<BR>> >URE Me(=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B ) =3D3D&lt=<BR>> >=3BBR&gt=3B&amp=3Bgt=3D3B VAR ptr : REF INTEGER :=3D3D NIL=3D3B BEGIN&lt=3B=<BR>> >BR&gt=3B&amp=3Bgt=3D3B ptr^ :=3D3D=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B 0&lt=3BBR&gt=3B&amp=3Bgt=3D3B END Me=3D3B&lt=3BBR&gt=3B&amp=<BR>> >=3Bgt=3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B BEGIN END Crash.&lt=3BBR&gt=3B&amp=<BR>> >=3Bgt=3D3B&lt=3BBR&gt=3B=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B &amp=3Bgt=3D3B Here's an example of what happens if you now call this=<BR>> > from an inter=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B acti=<BR>> >ve&lt=3BBR&gt=3B&amp=3Bgt=3D3B interpreter that catches the exception Runti=<BR>> >meError.E:&lt=3BBR&gt=3B=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B &amp=3Bgt=3D3B&lt=3BBR&gt=3B&amp=3Bgt=3D3B M-Scheme Experimental&lt=<BR>> >=3BBR&gt=3B&amp=3Bgt=3D3B LITHP ITH LITHENING.&lt=3BBR&gt=3B&amp=3B=3D<BR>&=<BR>> >gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B gt=3D3B&amp=3Bgt=3D3B (req=<BR>> >uire-modules "m3")&lt=3BBR&gt=3B&amp=3Bgt=3D3B #t&lt=3BBR&gt=3B&amp=3Bgt=3D=<BR>> >3B&amp=3Bgt=3D3B (Crash.Me=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B )&lt=3BBR&gt=3B&amp=3Bgt=3D3B EXCEPTION! RuntimeError! Attempt to=<BR>> > reference an illegal memory=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=<BR>> >=3B&gt=3B location.&lt=3BBR&gt=3B&amp=3Bgt=3D3B&amp=3Bgt=3D3B (+ 3 4)&lt=3B=<BR>> >BR&gt=3B&amp=3Bgt=3D3B 7&lt=3BBR&gt=3B&amp=3Bgt=3D3B&amp=3Bgt=3D3B&lt=3BBR&=<BR>> >gt=3B&amp=3Bgt=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B =3D3=<BR>> >B&lt=3BBR&gt=3B&amp=3Bgt=3D3B I just realized I may have broken pthreads=3D=<BR>> >2C let me go back=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B a=<BR>> >nd double-check it.&lt=3BBR&gt=3B&amp=3Bgt=3D3B runtime/POSIX and thread/PO=<BR>> >SIX don't refer=3D<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B to =<BR>> >the same thing do they...&lt=3BBR&gt=3B&amp=3Bgt=3D3B&lt=3BBR&gt=3B&amp=3Bg=<BR>> >t=3D3B Mika&lt=3BBR&gt=3B&amp=3Bgt=3D3B&lt=3BBR&gt=3B =3D<BR>&gt=3B &gt=3B&=<BR>> >gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &lt=3B/body&gt=3B<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B &lt=3B/html&gt=3B=3D<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B&gt=3B&=<BR>> >gt=3B&gt=3B --_a2a24b92-3b4c-456e-ab1b-c3f5e912854f_--<BR>&gt=3B &gt=3B&gt=<BR>> >=3B&gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &gt=3B&gt=3B&gt=3B&gt=3B<BR>&gt=3B &g=<BR>> >t=3B&gt=3B<BR> </body><BR>> ></html>=<BR>> ><BR>> >--_ab466c75-f74a-4983-8fec-4f513f45fe0b_--<BR>                                     </body>
</html>