From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andy Wingo Subject: bug#27476: libguile/memoize.c is not thread safe, so syntax parameter expansion is not thread-safe Date: Wed, 06 Feb 2019 17:14:37 +0100 Message-ID: <87o97o99n6.fsf@igalia.com> References: <87h8vvp1q7.fsf@elephly.net> <87377esu1a.fsf@gnu.org> <87k20nz18u.fsf@igalia.com> <87a81jj5gg.fsf@gnu.org> <87bmlyzxj7.fsf@elephly.net> <87shf44ny0.fsf@elephly.net> <878tfi9x15.fsf@gnu.org> <87h8nstms1.fsf@gnu.org> <874ljstlvq.fsf_-_@gnu.org> <87603x6x1f.fsf@igalia.com> <878t8tyyfk.fsf@gnu.org> <87lgct5e06.fsf@igalia.com> <87lg2t7z1o.fsf@gnu.org> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Return-path: Received: from eggs.gnu.org ([209.51.188.92]:39684) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1grPqq-0002Yt-Ic for bug-guix@gnu.org; Wed, 06 Feb 2019 11:15:06 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1grPqp-0001iD-MC for bug-guix@gnu.org; Wed, 06 Feb 2019 11:15:04 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:36815) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1grPqp-0001i2-BH for bug-guix@gnu.org; Wed, 06 Feb 2019 11:15:03 -0500 Sender: "Debbugs-submit" Resent-Message-ID: In-Reply-To: <87lg2t7z1o.fsf@gnu.org> ("Ludovic =?UTF-8?Q?Court=C3=A8s?="'s message of "Wed, 06 Feb 2019 15:48:51 +0100") List-Id: Bug reports for GNU Guix List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guix-bounces+gcggb-bug-guix=m.gmane.org@gnu.org Sender: "bug-Guix" To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 27476@debbugs.gnu.org Hi! On Wed 06 Feb 2019 15:48, Ludovic Court=C3=A8s writes: > I drew the conclusion that our syntax parameter is redefined when we > compile or when we load (guix monads), so there=E2=80=99s a chance that w= e get > to see the wrong value when we expand (guix monads) (I=E2=80=99m not enti= rely > sure about the exact sequence of events.) You are a wizard!!!! To be clear, here's the series of events. Firstly, know that defining a syntax parameter is like: (define name (make-syntax-transformer 'name 'syntax-parameter (list f))) So at the top level you end up with an association between a name and a "syntax transformer" object (see macros.[ch]). The syntax transformer object itself consists of its name (for debugging), its syntax type, and its syntax binding. For syntax parameters, the binding is a list containing a single element, the syntax transformer. This list is later used as a key into a compile-time environment, as it's a unique object associated with the syntax parameter. When (syntax-parameterize ((name f*)) exp) is seen, psyntax will look up `name' in the current expansion-time environment. It asserts that the name is bound to a syntax transformer and that the syntax transformer is indeed a syntax parameter, and extracts the associated binding `b'. Keep in bind that `b' is the single-element list containing the "default" syntax transformer `f'. syntax-parameterize then does something weird: it adds an association between the binding value `b' and `f*' to the expand-time environment. It does this because the `b' is just a fresh object, so it's a unique key that's usable for associations. (The way this works is my fault FWIW.) To be clear, it doesn't add a new definition of `name'; it instead establishes a new lexical binding for the unique object `b'. Then when a use of `name' is seen within `exp', Guile finds that `name' is a syntax parameter, extracts the binding from the syntax transformer object, then does a second lookup of that binding. If it finds something bound, it uses that, otherwise it uses the default binding. I think you see the race here. For an initial state of (define P (stx-param (list F))) we have: thread A thread B time resolve P | extract B | associate B and F* | | define P (stx-param (list F**)) resolve P | extract B (!) | resolve B (!) | see F** instead of F* (!) | v > So I came up with =E2=80=98define-syntax-parameter-once=E2=80=99, which i= s like > =E2=80=98define-once=E2=80=99 but for syntax parameters (note that we can= =E2=80=99t use > =E2=80=98define-once=E2=80=99 in =E2=80=98define-syntax-parameter-once=E2= =80=99 because it expands to a > reference to NAME, which doesn=E2=80=99t work for a macro): Your fix is good! But, it prevents redefinition of syntax parameters. I would like to work on a solution that instead of using this double-lookup, simply adds an association between P and F* in the environment, instead of doing the double-lookup thing. Probably that will be 3.0-only. For 2.2, we can probably update the compiler to trampoline through some kind of "redefine-syntax" or something that will do (set-car! B F**) instead of (define P (stx-param B*)). I.e. redefinition keeps the unique key there. Andy