aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-09-29 02:11:19 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-09-29 02:11:19 +0200
commit3b4d04b77eb5cfdb8ac6a799a3f3ccf1e455d0e7 (patch)
treef7486abff328ee79831a4c4ee6cc006a11006dc8
parent78c9c736ab13caec3f6c1032e39200fed5580f50 (diff)
downloadbusybox-w32-3b4d04b77eb5cfdb8ac6a799a3f3ccf1e455d0e7.tar.gz
busybox-w32-3b4d04b77eb5cfdb8ac6a799a3f3ccf1e455d0e7.tar.bz2
busybox-w32-3b4d04b77eb5cfdb8ac6a799a3f3ccf1e455d0e7.zip
ash: input: Allow two consecutive calls to pungetc
Upstream commit: input: Allow two consecutive calls to pungetc The commit ef91d3d6a4c39421fd3a391e02cd82f9f3aee4a8 ([PARSER] Handle backslash newlines properly after dollar sign) created cases where we make two consecutive calls to pungetc. As we don't explicitly support that there are corner cases where you end up with garbage input leading to undefined behaviour. This patch adds explicit support for two consecutive calls to pungetc. Reported-by: Jilles Tjoelker <jilles@stack.nl> Reported-by: Juergen Daubert <jue@jue.li> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> In bbox case, bashism >& may need two pungetc() too. function old new delta pgetc 514 555 +41 pushstring 114 144 +30 basepf 52 76 +24 popstring 134 151 +17 parse_command 1584 1585 +1 pungetc 12 9 -3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/1 up/down: 113/-3) Total: 110 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c77
1 files changed, 43 insertions, 34 deletions
diff --git a/shell/ash.c b/shell/ash.c
index a31cee259..a63d40d7e 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -1168,6 +1168,12 @@ struct strpush {
1168 struct alias *ap; /* if push was associated with an alias */ 1168 struct alias *ap; /* if push was associated with an alias */
1169#endif 1169#endif
1170 char *string; /* remember the string since it may change */ 1170 char *string; /* remember the string since it may change */
1171
1172 /* Remember last two characters for pungetc. */
1173 int lastc[2];
1174
1175 /* Number of outstanding calls to pungetc. */
1176 int unget;
1171}; 1177};
1172 1178
1173struct parsefile { 1179struct parsefile {
@@ -1180,6 +1186,12 @@ struct parsefile {
1180 char *buf; /* input buffer */ 1186 char *buf; /* input buffer */
1181 struct strpush *strpush; /* for pushing strings at this level */ 1187 struct strpush *strpush; /* for pushing strings at this level */
1182 struct strpush basestrpush; /* so pushing one is fast */ 1188 struct strpush basestrpush; /* so pushing one is fast */
1189
1190 /* Remember last two characters for pungetc. */
1191 int lastc[2];
1192
1193 /* Number of outstanding calls to pungetc. */
1194 int unget;
1183}; 1195};
1184 1196
1185static struct parsefile basepf; /* top level input file */ 1197static struct parsefile basepf; /* top level input file */
@@ -9715,6 +9727,8 @@ pushstring(char *s, struct alias *ap)
9715 g_parsefile->strpush = sp; 9727 g_parsefile->strpush = sp;
9716 sp->prev_string = g_parsefile->next_to_pgetc; 9728 sp->prev_string = g_parsefile->next_to_pgetc;
9717 sp->prev_left_in_line = g_parsefile->left_in_line; 9729 sp->prev_left_in_line = g_parsefile->left_in_line;
9730 sp->unget = g_parsefile->unget;
9731 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
9718#if ENABLE_ASH_ALIAS 9732#if ENABLE_ASH_ALIAS
9719 sp->ap = ap; 9733 sp->ap = ap;
9720 if (ap) { 9734 if (ap) {
@@ -9724,6 +9738,7 @@ pushstring(char *s, struct alias *ap)
9724#endif 9738#endif
9725 g_parsefile->next_to_pgetc = s; 9739 g_parsefile->next_to_pgetc = s;
9726 g_parsefile->left_in_line = len; 9740 g_parsefile->left_in_line = len;
9741 g_parsefile->unget = 0;
9727 INT_ON; 9742 INT_ON;
9728} 9743}
9729 9744
@@ -9751,6 +9766,8 @@ popstring(void)
9751#endif 9766#endif
9752 g_parsefile->next_to_pgetc = sp->prev_string; 9767 g_parsefile->next_to_pgetc = sp->prev_string;
9753 g_parsefile->left_in_line = sp->prev_left_in_line; 9768 g_parsefile->left_in_line = sp->prev_left_in_line;
9769 g_parsefile->unget = sp->unget;
9770 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
9754 g_parsefile->strpush = sp->prev; 9771 g_parsefile->strpush = sp->prev;
9755 if (sp != &(g_parsefile->basestrpush)) 9772 if (sp != &(g_parsefile->basestrpush))
9756 free(sp); 9773 free(sp);
@@ -9846,13 +9863,14 @@ preadfd(void)
9846 */ 9863 */
9847//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) 9864//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9848#define pgetc_debug(...) ((void)0) 9865#define pgetc_debug(...) ((void)0)
9866static int pgetc(void);
9849static int 9867static int
9850preadbuffer(void) 9868preadbuffer(void)
9851{ 9869{
9852 char *q; 9870 char *q;
9853 int more; 9871 int more;
9854 9872
9855 while (g_parsefile->strpush) { 9873 if (g_parsefile->strpush) {
9856#if ENABLE_ASH_ALIAS 9874#if ENABLE_ASH_ALIAS
9857 if (g_parsefile->left_in_line == -1 9875 if (g_parsefile->left_in_line == -1
9858 && g_parsefile->strpush->ap 9876 && g_parsefile->strpush->ap
@@ -9864,13 +9882,7 @@ preadbuffer(void)
9864 } 9882 }
9865#endif 9883#endif
9866 popstring(); 9884 popstring();
9867 /* try "pgetc" now: */ 9885 return pgetc();
9868 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9869 g_parsefile->left_in_line,
9870 g_parsefile->next_to_pgetc,
9871 g_parsefile->next_to_pgetc);
9872 if (--g_parsefile->left_in_line >= 0)
9873 return (unsigned char)(*g_parsefile->next_to_pgetc++);
9874 } 9886 }
9875 /* on both branches above g_parsefile->left_in_line < 0. 9887 /* on both branches above g_parsefile->left_in_line < 0.
9876 * "pgetc" needs refilling. 9888 * "pgetc" needs refilling.
@@ -9949,27 +9961,28 @@ preadbuffer(void)
9949 return (unsigned char)*g_parsefile->next_to_pgetc++; 9961 return (unsigned char)*g_parsefile->next_to_pgetc++;
9950} 9962}
9951 9963
9952#define pgetc_as_macro() \
9953 (--g_parsefile->left_in_line >= 0 \
9954 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
9955 : preadbuffer() \
9956 )
9957
9958static int 9964static int
9959pgetc(void) 9965pgetc(void)
9960{ 9966{
9961 pgetc_debug("pgetc_fast at %d:%p'%s'", 9967 int c;
9968
9969 pgetc_debug("pgetc at %d:%p'%s'",
9962 g_parsefile->left_in_line, 9970 g_parsefile->left_in_line,
9963 g_parsefile->next_to_pgetc, 9971 g_parsefile->next_to_pgetc,
9964 g_parsefile->next_to_pgetc); 9972 g_parsefile->next_to_pgetc);
9965 return pgetc_as_macro(); 9973 if (g_parsefile->unget)
9966} 9974 return g_parsefile->lastc[--g_parsefile->unget];
9967 9975
9968#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 9976 if (--g_parsefile->left_in_line >= 0)
9969# define pgetc_fast() pgetc() 9977 c = (signed char)*g_parsefile->next_to_pgetc++;
9970#else 9978 else
9971# define pgetc_fast() pgetc_as_macro() 9979 c = preadbuffer();
9972#endif 9980
9981 g_parsefile->lastc[1] = g_parsefile->lastc[0];
9982 g_parsefile->lastc[0] = c;
9983
9984 return c;
9985}
9973 9986
9974#if ENABLE_ASH_ALIAS 9987#if ENABLE_ASH_ALIAS
9975static int 9988static int
@@ -9977,11 +9990,11 @@ pgetc_without_PEOA(void)
9977{ 9990{
9978 int c; 9991 int c;
9979 do { 9992 do {
9980 pgetc_debug("pgetc_fast at %d:%p'%s'", 9993 pgetc_debug("pgetc at %d:%p'%s'",
9981 g_parsefile->left_in_line, 9994 g_parsefile->left_in_line,
9982 g_parsefile->next_to_pgetc, 9995 g_parsefile->next_to_pgetc,
9983 g_parsefile->next_to_pgetc); 9996 g_parsefile->next_to_pgetc);
9984 c = pgetc_fast(); 9997 c = pgetc();
9985 } while (c == PEOA); 9998 } while (c == PEOA);
9986 return c; 9999 return c;
9987} 10000}
@@ -10015,18 +10028,13 @@ pfgets(char *line, int len)
10015} 10028}
10016 10029
10017/* 10030/*
10018 * Undo the last call to pgetc. Only one character may be pushed back. 10031 * Undo a call to pgetc. Only two characters may be pushed back.
10019 * PEOF may be pushed back. 10032 * PEOF may be pushed back.
10020 */ 10033 */
10021static void 10034static void
10022pungetc(void) 10035pungetc(void)
10023{ 10036{
10024 g_parsefile->left_in_line++; 10037 g_parsefile->unget++;
10025 g_parsefile->next_to_pgetc--;
10026 pgetc_debug("pushed back to %d:%p'%s'",
10027 g_parsefile->left_in_line,
10028 g_parsefile->next_to_pgetc,
10029 g_parsefile->next_to_pgetc);
10030} 10038}
10031 10039
10032/* 10040/*
@@ -10043,6 +10051,7 @@ pushfile(void)
10043 pf->pf_fd = -1; 10051 pf->pf_fd = -1;
10044 /*pf->strpush = NULL; - ckzalloc did it */ 10052 /*pf->strpush = NULL; - ckzalloc did it */
10045 /*pf->basestrpush.prev = NULL;*/ 10053 /*pf->basestrpush.prev = NULL;*/
10054 /*pf->unget = 0;*/
10046 g_parsefile = pf; 10055 g_parsefile = pf;
10047} 10056}
10048 10057
@@ -11451,7 +11460,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11451 IF_ASH_ALIAS(if (c != PEOA)) 11460 IF_ASH_ALIAS(if (c != PEOA))
11452 USTPUTC(c, out); 11461 USTPUTC(c, out);
11453 } 11462 }
11454 c = pgetc_fast(); 11463 c = pgetc();
11455 } /* for (;;) */ 11464 } /* for (;;) */
11456 endword: 11465 endword:
11457 11466
@@ -11945,7 +11954,7 @@ xxreadtoken(void)
11945 setprompt_if(needprompt, 2); 11954 setprompt_if(needprompt, 2);
11946 startlinno = g_parsefile->linno; 11955 startlinno = g_parsefile->linno;
11947 for (;;) { /* until token or start of word found */ 11956 for (;;) { /* until token or start of word found */
11948 c = pgetc_fast(); 11957 c = pgetc();
11949 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 11958 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
11950 continue; 11959 continue;
11951 11960
@@ -12008,7 +12017,7 @@ xxreadtoken(void)
12008 setprompt_if(needprompt, 2); 12017 setprompt_if(needprompt, 2);
12009 startlinno = g_parsefile->linno; 12018 startlinno = g_parsefile->linno;
12010 for (;;) { /* until token or start of word found */ 12019 for (;;) { /* until token or start of word found */
12011 c = pgetc_fast(); 12020 c = pgetc();
12012 switch (c) { 12021 switch (c) {
12013 case ' ': case '\t': 12022 case ' ': case '\t':
12014 IF_ASH_ALIAS(case PEOA:) 12023 IF_ASH_ALIAS(case PEOA:)