From 1f80e6e69b0435d5d960ac11e9f05c46158c34f6 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 13 Sep 2023 16:39:08 +0100 Subject: [PATCH] Fix `if (0);"test"||fail()` 2v19 regression - strings after if(0) didn't get interpreted Ensure eval("1;;;")==1 - eval("1;")==1 before, but not eval("1;;") We hit this with minification in the AT library... If there's a string right after an if(0) it doesn't get parsed! This happens because since 2v19ish we're no longer storing string contents in RAM if we're not supposed to be executing. But we need to be sure we don't Lex too far ahead with execute=false set --- ChangeLog | 2 ++ src/jsparse.c | 13 ++++++++++--- tests/test_string_noparse.js | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 tests/test_string_noparse.js diff --git a/ChangeLog b/ChangeLog index 3c5dcacf68..e730364d30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ Bangle.js2: When rendering overlays, *do not* use the current FG/BG color for 1 bit overlays nRF52 SDK15: Fix UART when >1 central link enabled Bangle.js2: Allow 2 central links at once + Fix `if (0);"test"||fail()` 2v19 regression - strings after if(0) didn't get interpreted + Ensure eval("1;;;")==1 - eval("1;")==1 before, but not eval("1;;") 2v19 : Fix Object.values/entries for numeric keys after 2v18 regression (fix #2375) nRF52: for SD>5 use static buffers for advertising and scan response data (#2367) diff --git a/src/jsparse.c b/src/jsparse.c index d760a3bbdf..caac1b4cb4 100644 --- a/src/jsparse.c +++ b/src/jsparse.c @@ -2318,7 +2318,6 @@ NO_INLINE JsVar *jspeBlockOrStatement() { return 0; } else { JsVar *v = jspeStatement(); - if (lex->tk==';') JSP_ASSERT_MATCH(';'); return v; } } @@ -2330,6 +2329,7 @@ NO_INLINE JsVar *jspParse() { while (!JSP_SHOULDNT_PARSE && lex->tk != LEX_EOF) { jsvUnLock(v); v = jspeBlockOrStatement(); + while (lex->tk==';') JSP_ASSERT_MATCH(';'); jsvCheckReferenceError(v); } return v; @@ -2410,7 +2410,9 @@ NO_INLINE JsVar *jspeStatementIf() { JSP_SAVE_EXECUTE(); if (!cond) jspSetNoExecute(); JsExecFlags hasError = 0; - JsVar *a = jspeBlockOrStatement(); + JsVar *a = 0; + if (lex->tk!=';') + a = jspeBlockOrStatement(); hasError |= execInfo.execute&EXEC_ERROR_MASK; if (!cond) { jsvUnLock(a); @@ -2419,11 +2421,16 @@ NO_INLINE JsVar *jspeStatementIf() { } else { result = a; } + /* We must manually parse ';' here, because if we did it when execInfo.execute==false (eg `if(0);`) + then if a String comes straight after it wouldn't have been interpreted */ + if (lex->tk==';') JSP_ASSERT_MATCH(';'); if (lex->tk==LEX_R_ELSE) { JSP_ASSERT_MATCH(LEX_R_ELSE); JSP_SAVE_EXECUTE(); if (cond) jspSetNoExecute(); - JsVar *a = jspeBlockOrStatement(); + JsVar *a = 0; + if (lex->tk!=';') + a = jspeBlockOrStatement(); hasError |= execInfo.execute&EXEC_ERROR_MASK; if (cond) { jsvUnLock(a); diff --git a/tests/test_string_noparse.js b/tests/test_string_noparse.js new file mode 100644 index 0000000000..13a830e5cb --- /dev/null +++ b/tests/test_string_noparse.js @@ -0,0 +1,20 @@ +function fail(n) { + throw new Error("FAILED at "+n); +} + +/* We hit this with minification in the AT library... If there's a string right after an if(0) it +doesn't get parsed! + +This happens because since 2v19ish we're no longer storing string contents in RAM if +we're not supposed to be executing. But we need to be sure we don't Lex too far ahead +with execute=false set +*/ + +while (0) 1;"test"||fail("while") // ok +for (;0;);"test"||fail("for") // ok +if (1) 1;"test"||fail("if(1)1;") // ok +if (0) 1;"test"||fail("if(0)1;") // failed +if (0);"test"||fail("if(0);") // failed +if (1);else;"test"||fail("if(1);else;") // failed +// if we got here we're ok +result=1