From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Marius Vollmer Newsgroups: gmane.lisp.guile.devel Subject: Re: scm_leave_guile, setjmp, and caller-saved registers Date: Tue, 06 Dec 2005 21:10:16 +0200 Message-ID: <87u0dm3uuf.fsf@zagadka.de> References: <6bc7ed77da7c45cd76aec4ab9ddb4627@raeburn.org> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1133896419 27554 80.91.229.2 (6 Dec 2005 19:13:39 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Tue, 6 Dec 2005 19:13:39 +0000 (UTC) Cc: guile-devel@gnu.org Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Tue Dec 06 20:13:37 2005 Return-path: Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1EjiDH-0008Jf-95 for guile-devel@m.gmane.org; Tue, 06 Dec 2005 20:10:57 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1EjiDN-0002iG-Qe for guile-devel@m.gmane.org; Tue, 06 Dec 2005 14:11:01 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1EjiD3-0002Z9-LP for guile-devel@gnu.org; Tue, 06 Dec 2005 14:10:42 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1EjiD0-0002YA-DR for guile-devel@gnu.org; Tue, 06 Dec 2005 14:10:39 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1EjiCz-0002Y1-Mh for guile-devel@gnu.org; Tue, 06 Dec 2005 14:10:37 -0500 Original-Received: from [213.243.153.36] (helo=smtp3.pp.htv.fi) by monty-python.gnu.org with esmtp (Exim 4.34) id 1EjiDh-0001xO-SW for guile-devel@gnu.org; Tue, 06 Dec 2005 14:11:22 -0500 Original-Received: from zagadka.ping.de (cs181072157.pp.htv.fi [82.181.72.157]) by smtp3.pp.htv.fi (Postfix) with SMTP id 6F7B327ACF9 for ; Tue, 6 Dec 2005 21:10:22 +0200 (EET) Original-Received: (qmail 20473 invoked by uid 1000); 6 Dec 2005 19:10:16 -0000 Original-To: Ken Raeburn In-Reply-To: <6bc7ed77da7c45cd76aec4ab9ddb4627@raeburn.org> (Ken Raeburn's message of "Fri, 1 Jul 2005 18:17:13 -0400") User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:5463 Archived-At: Ken Raeburn writes: > Somebody please check me on this, I'm not sure if scm_leave_guile can > be relied upon to work. I believe everything you say is correct, unfortunately. I will make the change you propose to scm_without_guile and remove scm_leave_guile and scm_enter_guile. I will put your explanation next to scm_without_guile. The rest of your text since it is so old now (sorry): > Actually, it's the suspend() function inside it, in the current > implementation, but the issue extends to scm_leave_guile, and > scm_without_guile in its current implementation. > > Consider this sequence: > > Function foo, called in Guile mode, calls suspend (maybe indirectly > through scm_leave_guile), which does this: > > /* record top of stack for the GC */ > t->top = SCM_STACK_PTR (&t); // just takes address of automatic > var 't' > /* save registers. */ > SCM_FLUSH_REGISTER_WINDOWS; // sparc only > setjmp (t->regs); // here's most of the magic > > ... and returns. > > Function foo has a SCM value X, a handle on a non-immediate object, in > a caller-saved register R, and it's the only reference to the object > currently. > > The compiler wants to use R in suspend, so it pushes the current > value, X, into a stack slot which will be reloaded on exit from > suspend; then it loads stuff into R and goes about its business. The > setjmp call saves (some of) the current registers, including R, which > no longer contains X. (This isn't a problem for a normal > setjmp/longjmp situation, where longjmp would be called before > setjmp's caller returns; the old value for X would be loaded back from > the stack after the longjmp, before the function returned.) > > So, suspend returns, loading X back into R (and invalidating the jump > buffer) in the process. The caller foo then goes off and calls a > bunch of other functions out of Guile mode, occasionally storing X on > the stack again, but, say, much deeper on the stack than suspend's > stack frame went, and the stack slot where suspend had written X has > long since been overwritten with other values. > > Okay, nothing actively broken so far. Now, let garbage collection > run, triggered by another thread. > > The thread calling foo is out of Guile mode at the time, so the > garbage collector just scans a range of stack addresses. Too bad that > X isn't stored there. So the pointed-to storage goes onto the free > list, and I think you can see where things go from there. > > Is there anything I'm missing that'll prevent this scenario from > happening? I mean, aside from, "well, suspend and scm_leave_guile > don't have many local variables, so they probably won't need to save > any registers on most systems, so we hope everything will wind up in > the jump buffer and we'll just get away with it"? > > (And, going the other direction, if scm_leave_guile and suspend push > the stack pointer over onto a new page, and foo doesn't make further > function calls and thus the stack pointer no longer includes that > page, are we guaranteed that the kernel cannot release the now-unused > stack page that contains the top-of-stack pointer we just saved? I > don't know if any OS actually does that. If it does, we could get > faults in garbage collection.) > > I don't think scm_without_guile has to have this problem, as it gets > more control over the stack handling -- but it should call setjmp > itself. I'd probably try something like: > > /* record top of stack for the GC */ > t->top = SCM_STACK_PTR (&t); > /* save registers. */ > SCM_FLUSH_REGISTER_WINDOWS; > setjmp (t->regs); > res = func(data); > scm_enter_guile (t); > > ... though even that's making some assumptions about the stack > ordering of local variables versus caller-saved registers. > > For something like scm_leave_guile to work, I don't think it can just > rely on invalidated jump buffers. A valid jump buffer, and a handle > on the stack state at the point when the jump buffer was initialized, > together, would work fine, but I think then we're talking about macros > invoking setjmp in the caller's stack frame, and requiring that the > caller of scm_leave_guile also call scm_enter_guile before returning, > kind of like pthread_cleanup_push/pop calls that have to be paired up > in a function. (In fact, the pthread ones have to be paired up > syntactically, as if they might expand to a compound statement > incorporating the user's code, and invoking a compiler's > exception-handling primitives. Which might be something to think > about for cases where Guile is used with C++ exceptions or > pthread_cancel.) > > Ken > > > _______________________________________________ > Guile-devel mailing list > Guile-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/guile-devel -- GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405 _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel