Skip to content

Commit e51c9c1

Browse files
committed
40453: signal handler safety for callers of patcompile(PAT_STATIC), which is not re-entrant.
1 parent 0672c75 commit e51c9c1

File tree

13 files changed

+126
-42
lines changed

13 files changed

+126
-42
lines changed

ChangeLog

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
2017-01-28 Barton E. Schaefer <[email protected]>
22

3+
* 40453: Src/Modules/zpty.c, Src/Modules/zutil.c,
4+
Src/Zle/compctl.c, Src/Zle/complete.c, Src/Zle/computil.c,
5+
Src/Zle/zle_hist.c, Src/builtin.c, Src/cond.c, Src/glob.c,
6+
Src/loop.c, Src/options.c, Src/parse.c: signal handler safety
7+
for callers of patcompile(PAT_STATIC), which is not re-entrant.
8+
39
* 40439: Src/zsh.h: PAT_HEAPDUP definition just for clarity
410

511
2017-01-28 Peter Stephenson <[email protected]>

Src/Modules/zpty.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,8 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch)
544544
p = dupstring(args[1]);
545545
tokenize(p);
546546
remnulargs(p);
547-
if (!(prog = patcompile(p, PAT_STATIC, NULL))) {
547+
/* Signals handlers might stomp PAT_STATIC */
548+
if (!(prog = patcompile(p, PAT_ZDUP, NULL))) {
548549
zwarnnam(nam, "bad pattern: %s", args[1]);
549550
return 1;
550551
}
@@ -682,9 +683,14 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch)
682683
write_loop(1, buf, used);
683684
}
684685

685-
if (seen && (!prog || matchok || !mustmatch))
686-
return 0;
687-
return cmd->fin + 1;
686+
{
687+
int ret = cmd->fin + 1;
688+
if (seen && (!prog || matchok || !mustmatch))
689+
ret = 0;
690+
if (prog)
691+
freepatprog(prog);
692+
return ret;
693+
}
688694
}
689695

690696
static int

Src/Modules/zutil.c

+17-3
Original file line numberDiff line numberDiff line change
@@ -510,25 +510,33 @@ bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
510510
zwarnnam(nam, "too many arguments");
511511
return 1;
512512
}
513+
514+
queue_signals(); /* Protect PAT_STATIC */
515+
513516
if (context) {
514517
tokenize(context);
515518
zstyle_contprog = patcompile(context, PAT_STATIC, NULL);
516519

517-
if (!zstyle_contprog)
520+
if (!zstyle_contprog) {
521+
unqueue_signals();
518522
return 1;
523+
}
519524
} else
520525
zstyle_contprog = NULL;
521526

522527
if (stylename) {
523528
s = (Style)zstyletab->getnode2(zstyletab, stylename);
524-
if (!s)
529+
if (!s) {
530+
unqueue_signals();
525531
return 1;
532+
}
526533
zstyletab->printnode(&s->node, list);
527534
} else {
528535
scanhashtable(zstyletab, 1, 0, 0,
529536
zstyletab->printnode, list);
530537
}
531538

539+
unqueue_signals();
532540
return 0;
533541
}
534542
switch (args[0][1]) {
@@ -675,14 +683,20 @@ bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
675683
char **vals;
676684
Patprog prog;
677685

686+
queue_signals(); /* Protect PAT_STATIC */
687+
678688
tokenize(args[3]);
679689

680690
if ((vals = lookupstyle(args[1], args[2])) &&
681691
(prog = patcompile(args[3], PAT_STATIC, NULL))) {
682692
while (*vals)
683-
if (pattry(prog, *vals++))
693+
if (pattry(prog, *vals++)) {
694+
unqueue_signals();
684695
return 0;
696+
}
685697
}
698+
699+
unqueue_signals();
686700
return 1;
687701
}
688702
break;

Src/Zle/compctl.c

+25-7
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ freecompctlp(HashNode hn)
9999
}
100100

101101
/**/
102-
void
102+
static void
103103
freecompctl(Compctl cc)
104104
{
105105
if (cc == &cc_default ||
@@ -142,7 +142,7 @@ freecompctl(Compctl cc)
142142
}
143143

144144
/**/
145-
void
145+
static void
146146
freecompcond(void *a)
147147
{
148148
Compcond cc = (Compcond) a;
@@ -186,7 +186,7 @@ freecompcond(void *a)
186186
}
187187

188188
/**/
189-
int
189+
static int
190190
compctlread(char *name, char **args, Options ops, char *reply)
191191
{
192192
char *buf, *bptr;
@@ -1564,19 +1564,24 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
15641564
Compctl cc = NULL;
15651565
int ret = 0;
15661566

1567+
queue_signals();
1568+
15671569
/* clear static flags */
15681570
cclist = 0;
15691571
showmask = 0;
15701572

15711573
/* Parse all the arguments */
15721574
if (*argv) {
15731575
/* Let's see if this is a global matcher definition. */
1574-
if ((ret = get_gmatcher(name, argv)))
1576+
if ((ret = get_gmatcher(name, argv))) {
1577+
unqueue_signals();
15751578
return ret - 1;
1579+
}
15761580

15771581
cc = (Compctl) zshcalloc(sizeof(*cc));
15781582
if (get_compctl(name, &argv, cc, 1, 0, 0)) {
15791583
freecompctl(cc);
1584+
unqueue_signals();
15801585
return 1;
15811586
}
15821587

@@ -1604,6 +1609,7 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
16041609
printcompctl((cclist & COMP_LIST) ? "" : "DEFAULT", &cc_default, 0, 0);
16051610
printcompctl((cclist & COMP_LIST) ? "" : "FIRST", &cc_first, 0, 0);
16061611
print_gmatcher((cclist & COMP_LIST));
1612+
unqueue_signals();
16071613
return ret;
16081614
}
16091615

@@ -1642,6 +1648,7 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
16421648
printcompctl("", &cc_first, 0, 0);
16431649
if (cclist & COMP_LISTMATCH)
16441650
print_gmatcher(COMP_LIST);
1651+
unqueue_signals();
16451652
return ret;
16461653
}
16471654

@@ -1656,6 +1663,7 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
16561663
compctl_process_cc(argv, cc);
16571664
}
16581665

1666+
unqueue_signals();
16591667
return ret;
16601668
}
16611669

@@ -1667,12 +1675,18 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
16671675
static int
16681676
bin_compcall(char *name, UNUSED(char **argv), Options ops, UNUSED(int func))
16691677
{
1678+
int ret;
1679+
16701680
if (incompfunc != 1) {
16711681
zwarnnam(name, "can only be called from completion function");
16721682
return 1;
16731683
}
1674-
return makecomplistctl((OPT_ISSET(ops,'T') ? 0 : CFN_FIRST) |
1675-
(OPT_ISSET(ops,'D') ? 0 : CFN_DEFAULT));
1684+
1685+
queue_signals();
1686+
ret = makecomplistctl((OPT_ISSET(ops,'T') ? 0 : CFN_FIRST) |
1687+
(OPT_ISSET(ops,'D') ? 0 : CFN_DEFAULT));
1688+
unqueue_signals();
1689+
return ret;
16761690
}
16771691

16781692
/*
@@ -1756,6 +1770,8 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat)
17561770
int onm = nmatches, odm = diffmatches, osi = movefd(0);
17571771
LinkNode n;
17581772

1773+
queue_signals();
1774+
17591775
/* We build a copy of the list of matchers to use to make sure that this
17601776
* works even if a shell function called from the completion code changes
17611777
* the global matchers. */
@@ -1883,6 +1899,8 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat)
18831899
}
18841900
redup(osi, 0);
18851901
dat->lst = 1;
1902+
1903+
unqueue_signals();
18861904
return 0;
18871905
}
18881906

@@ -2044,7 +2062,7 @@ maketildelist(void)
20442062
/* This does the check for compctl -x `n' and `N' patterns. */
20452063

20462064
/**/
2047-
int
2065+
static int
20482066
getcpat(char *str, int cpatindex, char *cpat, int class)
20492067
{
20502068
char *s, *t, *p;

Src/Zle/complete.c

+10
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,8 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
896896
int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1;
897897
Patprog pp;
898898

899+
queue_signals(); /* Protect PAT_STATIC */
900+
899901
i = compcurrent - 1;
900902
if (i < 0 || i >= l)
901903
return 0;
@@ -930,6 +932,9 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
930932
t = 0;
931933
if (t && mod)
932934
restrict_range(b, e);
935+
936+
unqueue_signals();
937+
933938
return t;
934939
}
935940
case CVT_PRENUM:
@@ -952,6 +957,8 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
952957
{
953958
Patprog pp;
954959

960+
queue_signals(); /* Protect PAT_STATIC */
961+
955962
if (!na)
956963
return 0;
957964

@@ -1036,6 +1043,9 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
10361043
if (mod)
10371044
ignore_suffix(ol - (p - compsuffix));
10381045
}
1046+
1047+
unqueue_signals();
1048+
10391049
return 1;
10401050
}
10411051
}

Src/Zle/computil.c

+8
Original file line numberDiff line numberDiff line change
@@ -3928,6 +3928,8 @@ bin_comptry(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
39283928
if (*q) {
39293929
char *qq, *qqq;
39303930

3931+
queue_signals();
3932+
39313933
if (c)
39323934
*c = '\0';
39333935

@@ -3999,6 +4001,8 @@ bin_comptry(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
39994001
}
40004002
if (c)
40014003
*c = ':';
4004+
4005+
unqueue_signals();
40024006
}
40034007
}
40044008
if (num) {
@@ -4708,6 +4712,8 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped,
47084712
if (!*p)
47094713
continue;
47104714

4715+
queue_signals(); /* Protect PAT_STATIC */
4716+
47114717
tokenize(f);
47124718
pprog = patcompile(f, PAT_STATIC, NULL);
47134719
untokenize(f);
@@ -4740,6 +4746,8 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped,
47404746
}
47414747
}
47424748
}
4749+
4750+
unqueue_signals();
47434751
}
47444752
}
47454753
}

Src/Zle/zle_hist.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -1220,10 +1220,12 @@ doisearch(char **args, int dir, int pattern)
12201220
char *patbuf = ztrdup(sbuf);
12211221
char *patstring;
12221222
/*
1223-
* Do not use static pattern buffer (PAT_STATIC) since we call zle hooks,
1224-
* which might call other pattern functions. Use PAT_ZDUP instead.
1225-
* Use PAT_NOANCH because we don't need the match
1226-
* anchored to the end, even if it is at the start.
1223+
* Do not use static pattern buffer (PAT_STATIC) since we
1224+
* call zle hooks, which might call other pattern
1225+
* functions. Use PAT_ZDUP because we re-use the pattern
1226+
* in subsequent loops, so we can't pushheap/popheap.
1227+
* Use PAT_NOANCH because we don't need the match anchored
1228+
* to the end, even if it is at the start.
12271229
*/
12281230
int patflags = PAT_ZDUP|PAT_NOANCH;
12291231
if (sbuf[0] == '^') {

0 commit comments

Comments
 (0)