zsh-workers
 help / color / Atom feed
* [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap
@ 2019-11-11 14:38 ` Roman Perepelitsa
  2019-11-11 14:58   ` Peter Stephenson
  0 siblings, 1 reply; 7+ messages in thread
From: Roman Perepelitsa @ 2019-11-11 14:38 UTC (permalink / raw)
  To: Zsh hackers list

To reproduce:

1. Type `zsh -df`.
2. Type `trap ': $WIDGETSTYLE; return 130' INT`.
3. Press Ctrl-C.
4. Press Ctrl-C.

    % zsh -df
    adam% trap ': $WIDGETSTYLE; return 130' INT
    adam%
    adam% zsh: segmentation fault (core dumped)  zsh -df

Stack trace:

    #0  get_widgetstyle (pm=0x55d039ec4170) at zle_params.c:436
    #1  0x000055d03838591b in getstrvalue (v=0x7ffc0b0c23b0)
        at params.c:2196
    #2  0x000055d0383b34c5 in paramsubst (l=0x7fa2e862ee48,
        n=0x7fa2e862ee78, str=0x7ffc0b0c2480, qt=0, pf_flags=0,
        ret_flags=0x7ffc0b0c2594) at subst.c:2679
    #3  0x000055d0383ae44a in stringsubst (list=0x7fa2e862ee48,
        node=0x7fa2e862ee78, pf_flags=0, ret_flags=0x7ffc0b0c2594,
        asssub=0) at subst.c:322
    #4  0x000055d0383ad716 in prefork (list=0x7fa2e862ee48,
        flags=0, ret_flags=0x7ffc0b0c2594) at subst.c:142
    #5  0x000055d038338040 in execcmd_exec (state=0x7ffc0b0c2ec0,
        eparams=0x7ffc0b0c2ae0, input=0, output=0, how=2, last1=2,
        close_if_forked=-1) at exec.c:3178
    #6  0x000055d038334a3a in execpline2 (state=0x7ffc0b0c2ec0,
        pcode=131, how=2, input=0, output=0, last1=0) at exec.c:1930
    #7  0x000055d0383335dd in execpline (state=0x7ffc0b0c2ec0,
        slcode=4098, how=2, last1=0) at exec.c:1660
    #8  0x000055d038332880 in execlist (state=0x7ffc0b0c2ec0,
        dont_change_job=1, exiting=0) at exec.c:1415
    #9  0x000055d038331ebc in execode (p=0x55d039eb58f0,
        dont_change_job=1, exiting=0, context=0x55d0383dab37 "trap")
        at exec.c:1194
    #10 0x000055d0383ab02b in dotrapargs (sig=2,
        sigtr=0x55d038604648 <sigtrapped+8>, sigfn=0x55d039eb58f0)
        at signals.c:1381
    #11 0x000055d0383ab5c1 in dotrap (sig=2) at signals.c:1487
    #12 0x000055d0383aac14 in handletrap (sig=2) at signals.c:1202
    #13 0x000055d0383a9423 in zhandler (sig=2) at signals.c:670
    #14 <signal handler called>
    #15 0x00007fa2e7756081 in __GI___libc_read (fd=10,
        buf=0x7ffc0b0c44c3, nbytes=1)
        at ../sysdeps/unix/sysv/linux/read.c:27
    #16 0x00007fa2e5fdaead in raw_getbyte (do_keytmout=0,
        cptr=0x7ffc0b0c44c3 "\347\242\177", full=1)
        at zle_main.c:849
    #17 0x00007fa2e5fdb16e in getbyte (do_keytmout=0, timeout=0x0,
        full=1) at zle_main.c:884
    #18 0x00007fa2e5fd99ce in getkeybuf (w=0) at zle_keymap.c:1676
    #19 0x00007fa2e5fd9776 in getkeymapcmd (km=0x55d039eb81d0,
        funcp=0x7ffc0b0c4630, strp=0x7ffc0b0c4638)
        at zle_keymap.c:1587
    #20 0x00007fa2e5fd9a4c in getkeycmd () at zle_keymap.c:1705
    #21 0x00007fa2e5fdb945 in zlecore () at zle_main.c:1128
    #22 0x00007fa2e5fdc3e9 in zleread (lp=0x55d0385ffe20 <prompt>,
        rp=0x0, flags=3, context=0,
        init=0x7fa2e60065c0 "zle-line-init",
        finish=0x7fa2e60065b0 "zle-line-finish") at zle_main.c:1350
    #23 0x00007fa2e5fdf52b in zle_main_entry (cmd=1,
        ap=0x7ffc0b0c48c0) at zle_main.c:2119
    #24 0x000055d03835d876 in zleentry (cmd=1) at init.c:1616
    #25 0x000055d03835eb8d in inputline () at input.c:295
    #26 0x000055d03835e9d1 in ingetc () at input.c:228
    #27 0x000055d038350945 in ihgetc () at hist.c:408
    #28 0x000055d038368e99 in gettok () at lex.c:611
    #29 0x000055d038368576 in zshlex () at lex.c:275
    #30 0x000055d0383903b0 in parse_event (endtok=37) at parse.c:581
    #31 0x000055d03835995e in loop (toplevel=1, justonce=0)
        at init.c:150
    #32 0x000055d03835dd38 in zsh_main (argc=2, argv=0x7ffc0b0c4d88)
        at init.c:1770
    #33 0x000055d03830f0b7 in main (argc=2, argv=0x7ffc0b0c4d88)
        at ./main.c:93

Crash at zle_params.c:436 due to bindk being null:

    Widget widget = bindk->widget;

Roman.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap
  2019-11-11 14:38 ` [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap Roman Perepelitsa
@ 2019-11-11 14:58   ` Peter Stephenson
  2019-11-11 15:37     ` Daniel Shahaf
  2019-11-11 15:40     ` Roman Perepelitsa
  0 siblings, 2 replies; 7+ messages in thread
From: Peter Stephenson @ 2019-11-11 14:58 UTC (permalink / raw)
  To: Roman Perepelitsa, Zsh hackers list

On Mon, 2019-11-11 at 15:38 +0100, Roman Perepelitsa wrote:
> Crash at zle_params.c:436 due to bindk being null:
> 
>     Widget widget = bindk->widget;

Looks to me like returning the empty string in that case would be fine?

pws


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap
  2019-11-11 14:58   ` Peter Stephenson
@ 2019-11-11 15:37     ` Daniel Shahaf
  2019-11-11 15:40     ` Roman Perepelitsa
  1 sibling, 0 replies; 7+ messages in thread
From: Daniel Shahaf @ 2019-11-11 15:37 UTC (permalink / raw)
  To: zsh-workers

Peter Stephenson wrote on Mon, 11 Nov 2019 14:58 +00:00:
> On Mon, 2019-11-11 at 15:38 +0100, Roman Perepelitsa wrote:
> > Crash at zle_params.c:436 due to bindk being null:
> > 
> >     Widget widget = bindk->widget;
> 
> Looks to me like returning the empty string in that case would be fine?

Also in $WIDGETFUNC, just above.  Didn't check if there are other cases.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap
  2019-11-11 14:58   ` Peter Stephenson
  2019-11-11 15:37     ` Daniel Shahaf
@ 2019-11-11 15:40     ` Roman Perepelitsa
  2019-11-11 15:46       ` Peter Stephenson
  2019-11-12 14:56       ` Mikael Magnusson
  1 sibling, 2 replies; 7+ messages in thread
From: Roman Perepelitsa @ 2019-11-11 15:40 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Mon, Nov 11, 2019 at 3:58 PM Peter Stephenson
<p.stephenson@samsung.com> wrote:
>
> On Mon, 2019-11-11 at 15:38 +0100, Roman Perepelitsa wrote:
> > Crash at zle_params.c:436 due to bindk being null:
> >
> >     Widget widget = bindk->widget;
>
> Looks to me like returning the empty string in that case would be fine?

I don't know. I haven't sent a patch because I'm not sure whether the
fix should be right there in get_widgetstyle or somewhere earlier so
that bindk is not null to begin with.

I should've explained what I'm trying to do. I want to use a long
prompt for the current command line and a short prompt for complete
commands. Sort of like transient_rprompt option but instead of hiding
just right prompt I want to hide most of left prompt too. Here's a
short demo: https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/transient-prompt.gif.

Here's how I'm doing it:

- Set long prompt in precmd.
- Set short prompt in zle-line-finish and on SIGINT.

The code:

    set-long-prompt() { PROMPT='%~%# ' }
    precmd_functions=(set-long-prompt)

    set-short-prompt() {
      if [[ $PROMPT != '%# ' ]]; then
        PROMPT='%# '
        zle .reset-prompt
      fi
    }

    zle-line-finish() { set-short-prompt }
    zle -N zle-line-finish

    trap 'set-short-prompt; return 130' INT

One issue with this code is that after hitting Ctrl-C, set-long-prompt
doesn't get called, so I end up with a short current prompt. I don't
know why this happens but apparently I can work around this by adding
another precmd hook before set-current-prompt. This extra hook won't
be called after Ctrl-C but set-current-prompt will.

    do-nothing() {}
    precmd_functions=(do-nothing set-current-prompt)

Unfortunately, there are a few other cases where hitting Ctrl-C will
result in the current prompt ending up short rather than long. For
example, if I this Ctrl-C after typing this:

    autoload -U compinit
    compinit
    zstyle ':completion:*' menu select
    grep -i<TAB>

If I didn't trap SIGINT, Ctrl-C would simply close the completion menu
here without reexpanding prompt. But now prompt will become short. To
deal with this issue I tried changing my trap so that it doesn't reset
prompt if SIGINT arrives during completions:

    trap '[[ $WIDGETSTYLE == .expand-or-complete ]] || set-complete-prompt
          return 130' INT

Unfortunately it crashes zsh as I've described in the original email.
It also doesn't really solve the problem. If I press Ctrl-S to trigger
fwd-i-search and then hit Ctrl-C, I'll end up with short prompt, too.
fwd-i-search is not a completion widget, so the condition in my trap
doesn't help.

What I really want is to follow the same logic as transient_rprompt
but instead of hiding right prompt I want to change left prompt. Any
hints on how I should do this? I feel like I'm digging in the wrong
direction.

Roman.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap
  2019-11-11 15:40     ` Roman Perepelitsa
@ 2019-11-11 15:46       ` Peter Stephenson
  2019-11-12 14:56       ` Mikael Magnusson
  1 sibling, 0 replies; 7+ messages in thread
From: Peter Stephenson @ 2019-11-11 15:46 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On Mon, 2019-11-11 at 16:40 +0100, Roman Perepelitsa wrote:
> On Mon, Nov 11, 2019 at 3:58 PM Peter Stephenson
> <p.stephenson@samsung.com> wrote:
> > 
> > 
> > On Mon, 2019-11-11 at 15:38 +0100, Roman Perepelitsa wrote:
> > > 
> > > Crash at zle_params.c:436 due to bindk being null:
> > > 
> > >     Widget widget = bindk->widget;
> > Looks to me like returning the empty string in that case would be fine?
> I don't know. I haven't sent a patch because I'm not sure whether the
> fix should be right there in get_widgetstyle or somewhere earlier so
> that bindk is not null to begin with.

I think there are highly likely to be such cases.  Look in zlecore()
where bindk is set.  We test for bindk NULL there after reading it.
You've got an asynchronous event so you don't know where that's going to
happen.  (There's a good chance signals are actually blocked at *that*
point, I didn't follow that through, but this is just an example.)

The only alternative I can think of would be queuing signals in more
places, but that's quite a heavyweight change that requires a good deal
of thinking through.  I think a NULL check in both places is entirely
unobjectionable.

(That doesn't mean everything else is *ncessarily* great, obviously...)

pws


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap
  2019-11-11 15:40     ` Roman Perepelitsa
  2019-11-11 15:46       ` Peter Stephenson
@ 2019-11-12 14:56       ` Mikael Magnusson
  2019-11-13 16:11         ` Roman Perepelitsa
  1 sibling, 1 reply; 7+ messages in thread
From: Mikael Magnusson @ 2019-11-12 14:56 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Zsh hackers list

On 11/11/19, Roman Perepelitsa <roman.perepelitsa@gmail.com> wrote:
> On Mon, Nov 11, 2019 at 3:58 PM Peter Stephenson
> <p.stephenson@samsung.com> wrote:
>>
>> On Mon, 2019-11-11 at 15:38 +0100, Roman Perepelitsa wrote:
>> > Crash at zle_params.c:436 due to bindk being null:
>> >
>> >     Widget widget = bindk->widget;
>>
>> Looks to me like returning the empty string in that case would be fine?
>
> I don't know. I haven't sent a patch because I'm not sure whether the
> fix should be right there in get_widgetstyle or somewhere earlier so
> that bindk is not null to begin with.
>
> I should've explained what I'm trying to do. I want to use a long
> prompt for the current command line and a short prompt for complete
> commands. Sort of like transient_rprompt option but instead of hiding
> just right prompt I want to hide most of left prompt too. Here's a
> short demo:
> https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/transient-prompt.gif.
>
> Here's how I'm doing it:
>
> - Set long prompt in precmd.
> - Set short prompt in zle-line-finish and on SIGINT.
>
> The code:
>
>     set-long-prompt() { PROMPT='%~%# ' }
>     precmd_functions=(set-long-prompt)
>
>     set-short-prompt() {
>       if [[ $PROMPT != '%# ' ]]; then
>         PROMPT='%# '
>         zle .reset-prompt
>       fi
>     }
>
>     zle-line-finish() { set-short-prompt }
>     zle -N zle-line-finish
>
>     trap 'set-short-prompt; return 130' INT
>
> One issue with this code is that after hitting Ctrl-C, set-long-prompt
> doesn't get called, so I end up with a short current prompt.

Have you tried restoring the long prompt in zle-line-init instead?

-- 
Mikael Magnusson

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap
  2019-11-12 14:56       ` Mikael Magnusson
@ 2019-11-13 16:11         ` Roman Perepelitsa
  0 siblings, 0 replies; 7+ messages in thread
From: Roman Perepelitsa @ 2019-11-13 16:11 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: Zsh hackers list

On Tue, Nov 12, 2019 at 3:56 PM Mikael Magnusson <mikachu@gmail.com> wrote:
> Have you tried restoring the long prompt in zle-line-init instead?

No, I haven't. zle-line-init is a bit too late. Prompt is already
expanded and printed out at that point. I could still change PROMPT
there and call `zle reset-prompt` but it would be slower than changing
PROMPT in precmd. As I mentioned, I've found a workaround for the bug
that causes the first element of precmd_functions to get skipped over
after Ctrl-C, so the part of my code that restores long prompt works
correctly in all cases where I've tried it.

The unresolved problem is that my code calls set-short-prompt in some
cases when it shouldn't after Ctrl-C. zle can effectively be in two
states and I don't know how to distinguish between the two when my
SIGINT trap triggers.

Normal state: Keyboard input goes into BUFFER. When Ctrl-C is pressed
in this state, new prompt is created. When my SIGINT trap triggers, I
want to shorten prompt.

    Before Ctrl-C:
        /tmp% echo hello█

    After Ctrl-C:
        /tmp% echo hello
        /tmp% █

Modal state: Keyboard input goes into some place other than BUFFER.
When Ctrl-C is pressed, zle state changes to normal but a new prompt
is not created. When my SIGINT trap triggers, I want to do nothing.
(This is where my current code works incorrectly because it always
shortens prompt on SIGINT.)

    Before Ctrl-C:
        /tmp% grep -
        zsh: do you wish to see all 180 possibilities (45 lines)? █

    After Ctrl-C:
        /tmp% grep -█

    Before Ctrl-C:
        /tmp% echo hello
        bck-i-search: hell█

    After Ctrl-C:
        /tmp% █

How can I distinguish between these states? How can I figure out from
within a SIGINT trap whether zle will or won't create new prompt after
my trap function returns?

Roman.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, back to index

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20191111143952eucas1p2784d9821f292f2c9c136b19da5a56ade@eucas1p2.samsung.com>
2019-11-11 14:38 ` [BUG] Crash when accessing WIDGETSTYLE from SIGINT trap Roman Perepelitsa
2019-11-11 14:58   ` Peter Stephenson
2019-11-11 15:37     ` Daniel Shahaf
2019-11-11 15:40     ` Roman Perepelitsa
2019-11-11 15:46       ` Peter Stephenson
2019-11-12 14:56       ` Mikael Magnusson
2019-11-13 16:11         ` Roman Perepelitsa

zsh-workers

Archives are clonable: git clone --mirror http://inbox.vuxu.org/zsh-workers

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://inbox.vuxu.org/vuxu.archive.zsh.workers


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git