[git commit] bc: fix interactive read()

Denys Vlasenko vda.linux at googlemail.com
Tue Dec 25 18:37:23 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=53e569c06b12ef2cb9ef2ceeff92f04cfbf113e3
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 miscutils/bc.c | 51 ++++++++++++++++++++++++++-------------------------
 1 file changed, 26 insertions(+), 25 deletions(-)

diff --git a/miscutils/bc.c b/miscutils/bc.c
index 8b44d4425..79f981eaf 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -6753,6 +6753,7 @@ static BC_STATUS zbc_vm_process(const char *text)
 	s = zbc_parse_text_init(&G.prs, text); // does the first zbc_lex_next()
 	if (s) RETURN_STATUS(s);
 
+ IF_BC(check_eof:)
 	while (G.prs.l.lex != XC_LEX_EOF) {
 		BcInstPtr *ip;
 		BcFunc *f;
@@ -6760,34 +6761,34 @@ static BC_STATUS zbc_vm_process(const char *text)
 		dbg_lex("%s:%d G.prs.l.lex:%d, parsing...", __func__, __LINE__, G.prs.l.lex);
 		if (IS_BC) {
 #if ENABLE_BC
+			if (G.prs.l.lex == BC_LEX_SCOLON
+			 || G.prs.l.lex == XC_LEX_NLINE
+			) {
+				s = zbc_lex_next(&G.prs.l);
+				if (s) goto err;
+				goto check_eof;
+			}
+
 			s = zbc_parse_stmt_or_funcdef(&G.prs);
 			if (s) goto err;
 
-			// Check that next token is not bogus, and skip over
-			// stmt delimiter(s) - newlines and semicolons
-			s = 1; // s == 1 on first iteration only
-			for (;;) {
-				if (G.prs.l.lex == XC_LEX_EOF)
-					goto execute; // this goto avoids resetting 's' to zero
-				if (G.prs.l.lex != BC_LEX_SCOLON
-				 && G.prs.l.lex != XC_LEX_NLINE
-				) {
-					const char *err_at;
-					// Not newline and not semicolon
-					if (s == 0) // saw at least one NL/semicolon before it?
-						break; // yes, good
-//TODO: commolalize for other parse errors:
-					err_at = G.prs.l.lex_next_at ? G.prs.l.lex_next_at : "UNKNOWN";
-					bc_error_fmt("bad statement terminator at '%.*s'",
-						(int)(strchrnul(err_at, '\n') - err_at),
-						err_at
-					);
-					goto err;
-				}
-				// NL or semicolon: skip it, set s = 0, repeat
-				s = zbc_lex_next(&G.prs.l);
-				if (s) goto err;
+			// Check that next token is a correct stmt delimiter -
+			// disallows "print 1 print 2" and such.
+			if (G.prs.l.lex != BC_LEX_SCOLON
+			 && G.prs.l.lex != XC_LEX_NLINE
+			 && G.prs.l.lex != XC_LEX_EOF
+			) {
+				const char *err_at;
+//TODO: commonalize for other parse errors:
+				err_at = G.prs.l.lex_next_at ? G.prs.l.lex_next_at : "UNKNOWN";
+				bc_error_fmt("bad statement terminator at '%.*s'",
+					(int)(strchrnul(err_at, '\n') - err_at),
+					err_at
+				);
+				goto err;
 			}
+			// The above logic is fragile. Check these examples:
+			// - interative read() still works
 #endif
 		} else {
 #if ENABLE_DC
@@ -6807,7 +6808,7 @@ static BC_STATUS zbc_vm_process(const char *text)
 			bc_parse_reset(&G.prs); // includes bc_program_reset()
 			RETURN_STATUS(BC_STATUS_FAILURE);
 		}
- IF_BC(execute:)
+
 		dbg_lex("%s:%d executing...", __func__, __LINE__);
 		s = zbc_program_exec();
 		if (s) {


More information about the busybox-cvs mailing list