tcsh-org / tcsh

This is a read-only mirror of the tcsh code repository.
https://www.tcsh.org/
Other
232 stars 42 forks source link

$x:q:h crashes with out of memory #30

Closed alzwded closed 3 years ago

alzwded commented 3 years ago

The following snippet crashes with Out of memory on HEAD:

set x='a/b c/d.e'
echo $x:q:h

I have everything open to fix it, it's that I don't know which way it's supposed to work.

So, :h crashes. The code in sh.lex.c makes me believe it wanted to find any slash in the string, because short2str unquotes the string, and Strrchr then returns NULL, because Strrchr deals with the quoted string and QUOTE|'/' != '/', resulting in a negative number being passed to Strnsave which resulted in bad things.

But when calling $x:q:r or $x:q:e yield the full string and nothing, respectively. This confuses me, because the r and e code don't unquote the string.

So... are the htre supposed to work on a quoted string? Is a quoted / different from an unquoted /? In other words, should I fix all four of them to properly deal with quoted slashes, or fix he to not match a quoted slash (thus, failing to find any slashes on in sh.lex.c:1047?

I'm okay to fix it either way, and I will add autotests for the cases, I'm just not sure what is considered "normal". Well, "don't crash" would be normal, but since I'm here... 😄

Maybe it would be nice to also clarify what hrte do after q in the manpage.

alzwded commented 3 years ago

P.S., callstack:

tcsh$ set x='a/b c/d.e'
tcsh$ echo $x:q:h
Out of memory

Breakpoint 1, 0x00007ffff7671bd0 in _exit () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 ncurses-libs-5.9-14.20130511.el7_4.x86_64 nss-softokn-freebl-3.44.0-8.el7_7.x86_64
(gdb) where
#0  0x00007ffff7671bd0 in _exit () from /lib64/libc.so.6
#1  0x0000000000403726 in out_of_memory () at tc.alloc.c:70
#2  0x000000000043dc05 in smalloc (n=n@entry=18446744073702272004)
    at tc.alloc.c:529
#3  0x0000000000444dc9 in s_strnsave (
    s=s@entry=0x6f1400 L"\x80000061\x8000002f\x80000062\x80000020\x80000063\x8000002f\x80000064\x8000002e\x80000065", len=<optimized out>) at tc.str.c:443
#4  0x000000000041969e in domod (
    cp=cp@entry=0x6f1400 L"\x80000061\x8000002f\x80000062\x80000020\x80000063\x8000002f\x80000064\x8000002e\x80000065", type=<optimized out>) at sh.lex.c:1067
#5  0x0000000000409438 in setDolp (cp=<optimized out>) at sh.dol.c:870
#6  0x0000000000409d2a in DgetC (flag=flag@entry=1) at sh.dol.c:344
#7  0x000000000040a860 in Dword (bb=0x69b520) at sh.dol.c:211
#8  Dfix2 (v=<optimized out>) at sh.dol.c:150
#9  0x000000000040aa6f in Dfix (t=t@entry=0x6e4520) at sh.dol.c:102
#10 0x00000000004224d4 in execute (t=0x6e4520, wanttty=12087, 
    pipein=pipein@entry=0x0, pipeout=pipeout@entry=0x0, 
    do_glob=do_glob@entry=1) at sh.sem.c:192
#11 0x00000000004220d0 in execute (t=t@entry=0x675fc0, wanttty=12087, 
    pipein=pipein@entry=0x0, pipeout=pipeout@entry=0x0, 
    do_glob=do_glob@entry=1) at sh.sem.c:746
#12 0x0000000000405a7b in process (catch=1) at sh.c:2162
#13 0x0000000000404b19 in main (argc=<optimized out>, argv=0x7fffffffdae8)
    at sh.c:1430
alzwded commented 3 years ago

Actually, after giving it another thought, it's pretty clear how those four modifiers should work.

zoulasc commented 3 years ago

The problem is calling any(short2str(cp), '/') as you point out which erroneously finds a '/' in the string because the string does not have a slash since it is quoted. I will commit a fix.

zoulasc commented 3 years ago

Fixed on HEAD.

alzwded commented 3 years ago

Thanks!