From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 27270 invoked from network); 1 Nov 2021 09:48:01 -0000 Received: from zero.zsh.org (2a02:898:31:0:48:4558:7a:7368) by inbox.vuxu.org with ESMTPUTF8; 1 Nov 2021 09:48:01 -0000 ARC-Seal: i=1; cv=none; a=rsa-sha256; d=zsh.org; s=rsa-20210803; t=1635760081; b=JRG6ujXUbEeyIFoiY+IMBjr9+0nyXe/rmc+dzS0L/rLLoW8xptwFsF2rjbhZDD9eKZkUm//ayt ZhlmXQdU+PsVm0/9AUPJc6bJGmKhy/a8a6JyWpkGeKSc0X4NaV0SWxJWf44OLV3mabsG6CH7VA uGLThopC846Gf0h0qlpPYJAwLlLd/ZpW8QVsRyvg3/Yk0UlrO4/DXJ37V+NLJsPi9SHEs1V0ol RedxdZ56SZYClnmuI4hA6KTFYCO4LbIfsUEr/o5VUV6eaG+wvp3DpJYgT4bod9UE1y4VWILydx PHY2C1pGQJmMsPQA6v7i+0v8pb+PsYVipJRg10GYiSUfyg==; ARC-Authentication-Results: i=1; zsh.org; iprev=pass (shout01.mail.de) smtp.remote-ip=62.201.172.24; dkim=pass header.d=mail.de header.s=mailde202009 header.a=rsa-sha256; dmarc=pass header.from=mail.de; arc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed; d=zsh.org; s=rsa-20210803; t=1635760081; bh=mFWXlZWMfkNMRMMoRTuLg+VI/HB651t2XyfoGLxxgSA=; h=List-Archive:List-Owner:List-Post:List-Unsubscribe:List-Subscribe:List-Help: List-Id:Sender:Content-Transfer-Encoding:Content-Type:In-Reply-To: MIME-Version:Date:Message-ID:From:References:Cc:To:Subject:DKIM-Signature: DKIM-Signature; b=oeLxtFbvDM/xRiogIxuKvRSE8CWHfFjnvwD04yaYDHDNBawP6d4cITta0lCjhhSrBV6yKsO4uj udAtKb1cuG6ihI5XFHnOj82vPZafw4ouNd74awc7wc4C8Nsr+u3gT/mtTxh0Xp8ee9ZVQvPZGs BIJO7/8laO/4vCQkOX+jA6EjnlpEqHxPVVg+/SPu3XvijA0bggwCM0H2d3rPHih9UbYEr0C5Eu 3tzZfyaixR76hvnGax+1gna2/23lObSojKmN5v1wXiH0qRNItb2I/UUY9qct7ITrIqv2P0mlC3 t3ccIdhVnVlRe2ZkM5iYMr6ngQ9+Y76C/vmRdPXDfVS8Rg==; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zsh.org; s=rsa-20210803; h=List-Archive:List-Owner:List-Post:List-Unsubscribe: List-Subscribe:List-Help:List-Id:Sender:Content-Transfer-Encoding: Content-Type:In-Reply-To:MIME-Version:Date:Message-ID:From:References:Cc:To: Subject:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID; bh=oaGOEUR1GGn6Y9os7yNowmW/NBad5yWP6xzbwPHv9+8=; b=jlEO+eMDnoVUYVL7QAExvBKIXJ wr3twNCyuDLgM4GglaU373wTu2QdBRnI5Q7iskbDNCGt3Blajfae5QDl2iPWG0jKEj7iUmWH0JxBo IVFYRbM8AtdR+eWHxTSgzql0GQfHVtYHEYI+T5y/7C+vDm9oYIEYL/paT3oe0rUr0ANcV9RUdh3DA 85yk1zB8kE+7suYBu4hk8ZjATpZ+ICG8nZkh6XB7ylwgyHA6/g+1cWQPlO14UkpNQOH7HohQzOQdY VYQ3gDJ0M/q2LjaQ5smUCRVCFoXi6wJtIHYc+rQx4O4xcRR3vFyvd1SrMZICXYbigb6tQyo0LQy9v RtwST9Uw==; Received: from authenticated user by zero.zsh.org with local id 1mhTv7-000BVv-8k; Mon, 01 Nov 2021 09:48:01 +0000 Authentication-Results: zsh.org; iprev=pass (shout01.mail.de) smtp.remote-ip=62.201.172.24; dkim=pass header.d=mail.de header.s=mailde202009 header.a=rsa-sha256; dmarc=pass header.from=mail.de; arc=none Received: from shout01.mail.de ([62.201.172.24]:57303) by zero.zsh.org with esmtps (TLS1.3:TLS_AES_256_GCM_SHA384:256) id 1mhTuV-000BEp-O8; Mon, 01 Nov 2021 09:47:24 +0000 Received: from postfix01.mail.de (postfix02.bt.mail.de [10.0.121.126]) by shout01.mail.de (Postfix) with ESMTP id 1C86FA0B10; Mon, 1 Nov 2021 10:47:23 +0100 (CET) Received: from smtp02.mail.de (smtp02.bt.mail.de [10.0.121.212]) by postfix01.mail.de (Postfix) with ESMTP id 031F3A03C1; Mon, 1 Nov 2021 10:47:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=mail.de; s=mailde202009; t=1635760043; bh=mFWXlZWMfkNMRMMoRTuLg+VI/HB651t2XyfoGLxxgSA=; h=Subject:To:Cc:References:From:Date:In-Reply-To:From; b=jGaCz4fVpiC5YuXv4zPtgKpqHxjceOK2JSj+IOLFJutrzNz23JYHne0m8yjP2scg6 CCsdHaNj0IFhCTF0yqtyH2Uw+utAQwhpOZUnnNhFtu+5ed+oROQovA6gG9kNd8UVaU NamfH3vwuaPa1tq/yc65+JJhir/Qs7aWCgNhWnGIMGHqRlF8UmwLnfJx62BjV3KVjt wwinDMolpquYdKWCxoFUecrbWgNG6GujSU290WpykkmaEromCsinj8LXB2u9hxcRlo bA2CKn8EwvKGQAxHIbEaOVyPVTTVNm45SiRyvP7LP8FaPHO0NOKXd8mBay6lwPpF4C aOElHl9jXj+oA== Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by smtp02.mail.de (Postfix) with ESMTPSA id EFC52A05BF; Mon, 1 Nov 2021 10:47:19 +0100 (CET) Subject: Re: exit_function - strange behavior To: Bart Schaefer Cc: Zsh hackers list References: <8ce6fada-c1da-c64f-9eb2-ccce5250474a@mail.de> From: Tycho Kirchner Message-ID: Date: Mon, 1 Nov 2021 10:47:10 +0100 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit X-purgate: clean X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate-type: clean X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-purgate-size: 5299 X-purgate-ID: 154282::1635760042-0000784B-6467DA8B/0/0 X-Seq: 49542 Archived-At: X-Loop: zsh-workers@zsh.org Errors-To: zsh-workers-owner@zsh.org Precedence: list Precedence: bulk Sender: zsh-workers-request@zsh.org X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: Am 01.11.21 um 00:52 schrieb Bart Schaefer: > On Mon, Oct 25, 2021 at 5:53 PM Bart Schaefer wrote: >> >> There's definitely a bug in this somewhere because if the last command >> executed by the final subshell [is] an anonymous function call: >> >> zsh -fc '...; ( () { return 123 } )' >> >> then the zshexit hook is NEVER called. > > When an anonymous function (or probably any function) calls "exit", we > pass through this bit of code in builtin.c bin_break(): > > 5719 * > 5720 * If we are already exiting... give this all up as > 5721 * a bad job. > 5722 */ > 5723 if (stopmsg || (zexit(0, ZEXIT_DEFERRED), !stopmsg)) { > 5724 retflag = 1; > 5725 breaks = loops; > 5726 exit_pending = 1; > 5727 exit_level = locallevel; > 5728 exit_val = num; > > With ZEXIT_DEFERRED, zexit() always bails out here: > > 5842 /* Positive shell_exiting means we have been here before */ > 5843 if (from_where == ZEXIT_DEFERRED || > 5844 (shell_exiting++ && from_where != ZEXIT_NORMAL)) > 5845 return; > > We then eventually call zexit(exit_val, ZEXIT_NORMAL) from doshfunc(). > > If instead the function calls "return 123" and is the last command in > the subshell, we pass through this branch of execcmd_exec(): > > 4239 if (forked) { > 4240 /* > 4241 * So what's going on here then? Well, I'm glad you asked. > [...] > 4263 */ > 4264 for (i = 0; i < 10; i++) > 4265 if (fdtable[i] != FDT_UNUSED) > 4266 close(i); > 4267 closem(FDT_UNUSED, 1); > 4268 if (thisjob != -1) > 4269 waitjobs(); > 4270 _realexit(); > 4271 } > > The call to _realexit() bypasses the hook. This is the expected > behavior for "falling off the end" of a subshell, rather than > explicitly "exit"-ing. > > However, in > zsh -fc '( () { return 123 } )' > the parent shell optimizes away the subshell and we arrive here: > > 3596 /* > 3597 * If we are in a subshell environment anyway, say > we're forked, > 3598 * even if we're actually not forked because we know the > 3599 * subshell is exiting. This ensures SHLVL reflects > the current > 3600 * shell, and also optimises out any save/restore we'd need to > 3601 * do if we were returning to the main shell. > 3602 */ > 3603 if (type == WC_SUBSH) > 3604 forked = 1; > > This should not happen when there is an exit trap or an exit hook, I > think? However, I'm not following the comment reference to SHLVL -- > why would it not reflect the correct thing? I suppose the actual > correct thing is higher up the call stack, where we should not assert > that the subshell is exiting if the parent shell still has traps or > hooks to process, so that we really have forked here. > > As to this: > >> You can avoid that by having the subshell end with "return 123" >> instead of "exit 123", except for some reason (possibly a bug) when >> the -c option is used in which case return behaves like exit again. > > bin_break() treats "return" as synonymous with "exit" here: > > 5683 case BIN_RETURN: > 5684 if ((isset(INTERACTIVE) && isset(SHINSTDIN)) > 5685 || locallevel || sourcelevel) { > [...] > 5699 return lastval; > 5700 } > 5701 zexit(num, ZEXIT_NORMAL); /* else treat return as > logout/exit */ > > To Tycho's original question, this means there is no way to have an > exit hook or trap called exactly when the original shell exits. You > can't forcibly finish a subshell before it "falls off the end" without > possibly invoking the trap and hook, and you can't even reliably test > $ZSH_SUBSHELL inside the hook, because the parent might optimize out a > fork without decrementing that. > > [[ $sysparams[pid] = $$ ]] almost gets there, except that you can't > assure the hook itself won't be skipped by a function that calls exit. > Bart, thanks for diving into this, I hope it can be fixed. I just wanted to point out that the documentation of $ZSH_SUBSHELL needs to be fixed as well: ZSH_SUBSHELL Readonly integer. Initially zero, incremented each time the shell forks to create a subshell for executing code. Hence ‘(print $ZSH_SUBSHELL)’ and ‘print $(print $ZSH_SUBSHELL)’ output 1, while ‘( (print $ZSH_SUBSHELL) )’ outputs 2. So $ZSH_SUBSHELL may also be incremented, if the shell did _not_ fork: % zsh -fc 'zmodload zsh/system; echo parent_pid: $$; echo parent_subshell $ZSH_SUBSHELL ; ( echo sysparams_pid: $sysparams[pid]; read -d " " pid < /proc/self/stat; echo proc_pid: $pid; echo child_subshell: $ZSH_SUBSHELL ; exit 123 )' parent_pid: 20562 parent_subshell 0 sysparams_pid: 20562 proc_pid: 20562 child_subshell: 1 Anyway, I think it is ok for $ZSH_SUBSHELL to be inconsistent with $sysparams[pid] as the fork-optimization is an implementation detail and most users probably want to know whether being in enclosed '( )'.