From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <0x66726565@gmail.com> Received: from mail-io1-xd2e.google.com (mail-io1-xd2e.google.com [IPv6:2607:f8b0:4864:20::d2e]) by sourceware.org (Postfix) with ESMTPS id 633E93858004 for ; Thu, 29 Oct 2020 07:50:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 633E93858004 Received: by mail-io1-xd2e.google.com with SMTP id k6so2391037ior.2 for ; Thu, 29 Oct 2020 00:50:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=ev5oj1WdFr/a3kyfvcmZlGPSa8zT3/WiKunmeUOEgPM=; b=nMfPWSkZONKdFijW6oMiOTZsoMlPxn4GU/OsCrQHX4smasC9P4KI19cH6CYWOdQtgR PBOO3R/2Ipr8hGHFjGgzaJXxapdspVK5iV29kavRjzhZkmM9w6woM/V8DKRasAUGcLqE Q0oaS8H8IvtkF41iqu5H6COPlhyz6xIw31UJZ/XbMD3H9w4x4Dh3PnGIkWQ3Mxno+zjA lbMCihVv7d47+BLFdNAuEmfIzXZywPqOz8XWV5E1U9SseRODRfAREAoMG4igevLbPptE olk943AsYI67rf36FcTnaKrCq+5Co5wfi3sZhGdDqCk10BHqHOmGDo7dfMqzCEzdpTah rstA== X-Gm-Message-State: AOAM533iypoOiQxpJH95G6GvR9pEEvVsFyMWE1G6o+XVtu6XzspOvEr4 Xkr1jfc/fMuZvX7Hj7WuaLEQ82NH2+S8d30CRIwN86xp5A== X-Google-Smtp-Source: ABdhPJza2/eai82SNWl4DccCCsV7JrzqqaFLMj5DISfBD0cHNaU4fYX0XbUo7ynfiuo4AQKbgm5NmO7+aEi7lc+iLTE= X-Received: by 2002:a6b:d21a:: with SMTP id q26mr2450947iob.128.1603957812518; Thu, 29 Oct 2020 00:50:12 -0700 (PDT) MIME-Version: 1.0 References: <25b5791b-5368-7a78-f80d-5ceb2b618d72@linaro.org> <518e2a7c-74a3-d5dc-52c3-3fdddd5f7fa4@linaro.org> <76680377-32fb-bf34-5c1e-2dc63d1485c7@linaro.org> <569317ca-b87a-68cc-a776-f524ec76ca3c@linaro.org> In-Reply-To: <569317ca-b87a-68cc-a776-f524ec76ca3c@linaro.org> From: Tadeus Prastowo <0x66726565@gmail.com> Date: Thu, 29 Oct 2020 08:50:01 +0100 Message-ID: Subject: Re: raise() marked __leaf__ is not C-compliant? To: Adhemerval Zanella Cc: "libc-help@sourceware.org" , Florian Weimer Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-3.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-help@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-help mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 29 Oct 2020 07:50:15 -0000 On Wed, Oct 28, 2020 at 9:17 PM Adhemerval Zanella wrote: > > On 28/10/2020 16:23, Tadeus Prastowo wrote: > > On Wed, Oct 28, 2020 at 6:34 PM Adhemerval Zanella > > wrote: > >> > >> On 28/10/2020 10:19, Tadeus Prastowo wrote: > >>> > >>> However, C, including C99, C11, and the latest C18 [1], says: "If a > >>> signal handler is called, the raise function shall not return until > >>> after the signal handler does." And, POSIX [2] says: "If a signal > >>> handler is called, the raise() function shall not return until after > >>> the signal handler does." So, the sentence "raise() definitely runs a > >>> signal handler" is valid in a portable sense as required by the > >>> standards, no? > >> > >> My understanding is it allows synchronous signals, not enforce it; > >> and if the signal is synchronous then it should complete prior hand. > > > > I understand your point as the C standard says: > > > > [...] distinct values that are the signal numbers, each corresponding > > to the specified condition: > > SIGABRT [...] > > SIGFPE [...] > > SIGILL [...] > > SIGINT [...] > > SIGSEGV [...] > > SIGTERM [...] > > An implementation need not generate any of these signals, except as a > > result of explicit calls to the raise function. [...] The complete > > set of signals, their semantics, and their default handling is > > implementation-defined; all signal numbers shall be positive. > > > > [...] > > > > void (*signal(int sig, void (*func)(int)))(int); > > Description > > [...] > > When a signal occurs and func points to a function, it is > > implementation-defined whether the equivalent of signal(sig, SIG_DFL); > > is executed [...]; in the case of SIGILL, the implementation may > > alternatively define that no action is taken. Then the equivalent of > > (*func)(sig); is executed. > > > > End quote. > > > > So, yes, you are right that the sentence "raise() definitely runs a > > signal handler" is inaccurate because, as quoted above, C standard > > allows an implementation to not run the handler that the user has > > designated to handle the signal being generated by raise(). However, > > if the implementation decides that "the equivalent of (*func)(sig); is > > executed", then the C standard requires that "the raise function shall > > not return until after the signal handler does." > > I agree this does make sense for *synchronous* signal triggering. My > point ir neither C not POSIX specify which signal should be synchronous. > In fact, afaik neither standard does make a clearly distinction nor > specific the expected semantic for signal "synchronicity" (it is really > implementation defined). I am sorry that after I re-read the quoted C standard, the correct understanding is that the implementation is required to execute "the equivalent of (*func)(sig);" if the registration of `func' using signal() is successful (i.e., signal() does not return SIG_ERR). This is because the C standard says: "When a signal occurs and func points to a function, it is implementation-defined whether [...]. Then the equivalent of (*func)(sig); is executed." Hence, if an implementation decides not to execute `func' for a certain implementation-defined signal (e.g., SIGKILL), then the call signal(SIGKILL, func) must return SIG_ERR, which is already the case. Otherwise, the C standard requires the implementation to run the signal handler `func'. However, before executing `func', the C standard allows the implementation to perform some setup, such as executing the equivalent of signal(sig, SIG_DFL);, but no matter what the setup does, the outcome of the setup will not cancel the execution of `func' owing to the fact that, by signal() not returning SIG_ERR, `func' is already required to be executed after the setup, which is already the case as demonstrated by the following program on SIGILL on which the C standard allows an implementation to perform no setup at all. #include static int val; void handler(int signo) { val = 1; } int main(int argc, char **argv) { signal(SIGILL, handler); raise(SIGILL); return val; } > > To conclude, in my earlier post, I meant to say: Glibc-2.30 raise() > > may run a signal handler that is defined in the current compilation > > unit to use static variables. So, unless the C standard says that it > > is an undefined behavior to access a non-volatile object with static > > storage duration from within a signal handler that is called > > synchronously by raise() on a normal execution path, the marking of > > raise() with __leaf__ makes raise() non-compliant with the C standard. Hence, while it is indeed true that the sentence "raise() definitely runs a signal handler" is inaccurate, it is inaccurate not because the implementation is allowed by the C standard to not run the handler that is successfully registered using signal() but because no handler has been registered successfully using signal() in the first place. > I am not a language lawyer here, and I agree with you that adding leaf > attribute on 'raise' is wrong. Thank you for your agreement. > But because glibc can't guarantee how > the underlying kernel will trigger the signal in a raise syscall. By striving to be comformant to the C standard, glibc has to guarantee the behavior that the C standard does not state as undefined/unspecified/implementation-defined, which in this case is the behavior that, after a signal handler is successfully registered using signal() and then the handled signal is generated using raise(), "the raise function shall not return until after the signal handler does", doesn't it? > I still think that once you can't assume the signal will be triggered > synchronously, you can't also assume that accessing non-volatile object > with static storage duration from within a signal handler might not > trigger undefined behavior. Isn't that by the C standard, which makes no distinction between synchronous and asynchronous signals and so allows me to not make any assumption about them, no undefined behavior results from accessing a non-volatile object with static storage duration from within a signal handler whose signal is generated using raise() on the normal execution path? Thank you for your patience in perusing my message. -- Best regards, Tadeus