Skip to content

Commit 7a2d356

Browse files
committed
emacs/vi: Fix <Tab> behaviour after command substitution
Tab completion in emacs and vi wrongly parses and executes command substitutions. Example reproducers: $ $(~)<Tab> # Result: $ $(~)ksh[1]: /home/johno: cannot execute [Is a directory] $ $(~ksh)<Tab> # Result: $ $(~ksh)ksh: /home/johno/GitRepos/KornShell/ksh: cannot execute [Is a directory] $ $(echo true)<Tab> # Result: $ /usr/bin/true # or just 'true' -- it's unpredictable In addition, backtick command substitutions had the following bug: $ `echo hi`<Tab> # Result: $ `echo hi`ksh: line 1: BUG_BRACQUOT_test.sh: not found (where BUG_BRACQUOT_test.sh happens to be lexically the first-listed file in my ksh development working directory). There's also a crash associated with this due to an access beyond buffer boundaries, which is only triggered on some systems (macOS included). src/cmd/ksh93/edit/completion.c: - find_begin(): * When finding the beginning of a command substitution and the last character is ')', do not increase the character pointer cp. Increasing it caused the condition 'if(c && c==endchar)' in the 'default:' block to be true, causing 'return(xp);' to be executed, which returns a pointer the beginning of the command substitution to ed_expand() on line 290, so that ed_expand() eventually executes the command substitution with the sh_argbuild() call on line 349. After deleting this 'else cp++', that statement 'if(c && c==endchar) return(xp);' is not executed and `find_begin()` returns the null pointer, which avoids anything being executed. Thanks to @JohnoKing: #268 (comment) * Add code for properly skipping over backtick-style command substitutions, based on the $( ) code. - ed_expand(): Avoid out[-1] reading one byte to the left of outbuff by first checking that out>outbuff. Thanks to @JohnoKing for using ASan to find the location of the crash: #268 (comment) src/cmd/ksh93/tests/pty.sh: - Test for the bugs detailed above. Resolves: #268
1 parent 33269ca commit 7a2d356

2 files changed

Lines changed: 24 additions & 4 deletions

File tree

src/cmd/ksh93/edit/completion.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,16 @@ static char *find_begin(char outbuff[], char *last, int endchar, int *type)
173173
xp = find_begin(cp,last,')',type);
174174
if(*(cp=xp)!=')')
175175
bp = xp;
176-
else
177-
cp++;
178176
}
179177
break;
178+
case '`':
179+
if(inquote=='\'')
180+
break;
181+
*type = mode;
182+
xp = find_begin(cp,last,'`',type);
183+
if(*(cp=xp)!='`')
184+
bp = xp;
185+
break;
180186
case '=':
181187
if(!inquote)
182188
{
@@ -447,9 +453,9 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count)
447453
out = overlaid(begin,*com++,nocase);
448454
}
449455
mode = (out==saveout);
450-
if(out[-1]==0)
456+
if(out>outbuff && out[-1]==0)
451457
out--;
452-
if(mode && out[-1]!='/')
458+
if(mode && (out==outbuff || out>outbuff && out[-1]!='/'))
453459
{
454460
if(cmd_completion)
455461
{

src/cmd/ksh93/tests/pty.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,5 +858,19 @@ w test \$\{.sh.level\t
858858
r ^:test-1: test \$\{.sh.level\}\r\n$
859859
!
860860

861+
# err_exit #
862+
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
863+
L tab completion executes command substitutions
864+
# https://github.com/ksh93/ksh/issues/268
865+
866+
d 15
867+
p :test-1:
868+
w $(echo true)\t
869+
r ^:test-1: \$\(echo true\)\r\n$
870+
p :test-2:
871+
w `echo true`\t
872+
r ^:test-2: `echo true`\r\n$
873+
!
874+
861875
# ======
862876
exit $((Errors<125?Errors:125))

0 commit comments

Comments
 (0)