From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from primenet.com.au (ns1.primenet.com.au [203.24.36.2]) by inbox.vuxu.org (OpenSMTPD) with ESMTP id 85816100 for ; Sun, 17 Feb 2019 04:41:18 +0000 (UTC) Received: (qmail 3139 invoked by alias); 17 Feb 2019 04:41:00 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: List-Unsubscribe: X-Seq: 44067 Received: (qmail 714 invoked by uid 1010); 17 Feb 2019 04:41:00 -0000 X-Qmail-Scanner-Diagnostics: from mail-it1-f195.google.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.100.2/25112. spamassassin: 3.4.2. Clear:RC:0(209.85.166.195):SA:0(-2.0/5.0):. Processed in 0.795297 secs); 17 Feb 2019 04:41:00 -0000 X-Envelope-From: hotpxless@gmail.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _netblocks.google.com designates 209.85.166.195 as permitted sender) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=QOIIfAovQ9q+Ebu/WS8sFuu+RwEjB1M6m/nvkJD6VZY=; b=gGrb80oFCPe/Lftaz4RapV8xArrfN336qrRhv9UXNYc8oYYyDHuztog0shVVOoSCIv 8SM0aJSYUhUu9ZOgIdiEadhfd2Ukuizv4gDZ/wZT1A/zpJHgHv0sGeGdEaC7zbjzLjYU vTKooLIEvx7/Ak/vkzC154hNRO6g92mK05F1PgqIKCbc1t+gZ8W+F02uSDbKNTeFgzVm j1+hO2gvQOgcKWhdcIbV9Qv0V8iTNN+tsvnbgWJrq0KBBUudYxdYpqb1TC5WjDcGyUn/ DBmbt8rKioc2O2I5rkIa4miu9gW9JfCrh6jnh3EtBxZX1B6gmdIWsIaXQn2sQgjOY2Md 64HA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=QOIIfAovQ9q+Ebu/WS8sFuu+RwEjB1M6m/nvkJD6VZY=; b=NEmunn/jJ2EIwgRmDSfIhElgtoeiqf+EANFXMfpn6ImclC+2YzbBb4Q/u8Vf5epm7W uqQ1ZEYbdHZ+Iy3QblpBQumZ5e2WHk6asQEhrp2PLT0rtekNwC19tVGKaIt6swJoZ7VY BnE2aeCM64M9kpHnr2QSwYcn/ZX+w050t76+qbJrPJuQMZQqUhU/43+QGUZ+gbvRLVaV 8pncLH0fr31JJ9/3vz+EMyMEXiG8Aq7xOovFytt+0KKDpM1eau27a6fzL5z2bVJLDd2G /LLXqw1pJg85vgDzQeYb5umcaeLvMSu/B1sUbvXvq/szyZkBkx2gUfTFebU+FUBywYjJ TPOw== X-Gm-Message-State: AHQUAuaMcZtj7SbX/HMIaUHMUZVg/XtGoNrixyJLuBsPc3OjOhbjLb2s 1c8/AQMFJdbs3j/OFPvXgMYNVSOOU7XoW4DLpPYPFg== X-Google-Smtp-Source: AHgI3IZZ/5tgZqxZUJe1Ss6WQd5cDP7mfN84Kyew+4oBqQwvaHcjoHWWF6JvdDqX7RB1A7EUkb92N7t45cK4nz8zmKQ= X-Received: by 2002:a02:3b51:: with SMTP id i17mr4857538jaf.68.1550378426048; Sat, 16 Feb 2019 20:40:26 -0800 (PST) MIME-Version: 1.0 From: Yutian Li Date: Sat, 16 Feb 2019 23:40:15 -0500 Message-ID: Subject: [PATCH] Fix an issue where SIGINT leaves readhistfile in inconsistent state To: zsh-workers@zsh.org Content-Type: text/plain; charset="UTF-8" Dear all, Thanks for perfecting this wonderful project. I've been using it for years, and it's my first time trying to contribute back to the community. So definitely let me know if my patch needs more work. :) The issue I encountered is, when Zsh receives a SIGINT, it sets errflag |= ERRFLAG_INT so it will break out of the loop in readhistfile. But before we entered this loop we have already set lasthist.fsiz = sb.st_size and lasthist.mtim = sb.st_mtime so it looks like we have processed the history file up to the end already. And next time readhistfile is called, it will skip all processing and assume we have the entire history. This leaves Zsh in an inconsistent state, where history from different sessions could be lost. As a quick reproduction, setopt share_history, set HISTFILE accordingly and open two sessions. In one session, do a bunch of ``` echo a echo b echo c echo d ``` Then in the second session, do ``` history ``` In the history shown, you'll only see `echo a` but not the rest. The reason is after Zsh processed the first line, and since Ctrl-C sets `ERRFLAG_INT`, it will stop processing histories but think it has processed everything up to the end of the file. So now that history is basically eaten up. And worse still, if the history file gets truncated/rewritten/`fc -W` at the end of the session, that history will be lost forever. My proposed fix is to just add another flag to tell us if we've been interrupted from last time. If so, we don't skip processing. Thanks, Yutian diff --git a/Src/hist.c b/Src/hist.c index dbdc1e4e5..e3950e064 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -216,6 +216,7 @@ static struct histfile_stats { char *text; time_t stim, mtim; off_t fpos, fsiz; + int interrupted; zlong next_write_ev; } lasthist; @@ -2544,11 +2545,13 @@ readhistfile(char *fn, int err, int readflags) sb.st_size == 0) return; if (readflags & HFILE_FAST) { - if ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime) - || lockhistfile(fn, 0)) + if (!lasthist.interrupted && + ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime) + || lockhistfile(fn, 0))) return; lasthist.fsiz = sb.st_size; lasthist.mtim = sb.st_mtime; + lasthist.interrupted = 0; } else if ((ret = lockhistfile(fn, 1))) { if (ret == 2) { zwarn("locking failed for %s: %e: reading anyway", fn, errno); @@ -2694,8 +2697,10 @@ readhistfile(char *fn, int err, int readflags) */ if (uselex || remeta) freeheap(); - if (errflag & ERRFLAG_INT) + if (errflag & ERRFLAG_INT) { + lasthist.interrupted=1; break; + } } if (start && readflags & HFILE_USE_OPTIONS) { zsfree(lasthist.text);