diff --git a/Units/parser-r6class.r/r6-null-pointer-regression.d/args.ctags b/Units/parser-r6class.r/r6-null-pointer-regression.d/args.ctags new file mode 100644 index 0000000000..b7cf2e4283 --- /dev/null +++ b/Units/parser-r6class.r/r6-null-pointer-regression.d/args.ctags @@ -0,0 +1,4 @@ +--sort=no +--fields=+ilaKSe{extras} +--extras=-p + diff --git a/Units/parser-r6class.r/r6-null-pointer-regression.d/expected.tags b/Units/parser-r6class.r/r6-null-pointer-regression.d/expected.tags new file mode 100644 index 0000000000..885dd36041 --- /dev/null +++ b/Units/parser-r6class.r/r6-null-pointer-regression.d/expected.tags @@ -0,0 +1,3 @@ +TestCase1 input.r /^TestCase1 <- R6::SomethingElse("TestCase1")$/;" globalVar language:R end:6 +TestCase2 input.r /^TestCase2 <- R6::$/;" globalVar language:R end:10 +TestCase3 input.r /^TestCase3 <- R6::R6Clas("TestCase3")$/;" globalVar language:R end:12 diff --git a/Units/parser-r6class.r/r6-null-pointer-regression.d/input.r b/Units/parser-r6class.r/r6-null-pointer-regression.d/input.r new file mode 100644 index 0000000000..2855830cef --- /dev/null +++ b/Units/parser-r6class.r/r6-null-pointer-regression.d/input.r @@ -0,0 +1,13 @@ +# Test case for R6 parser null pointer regression +# This triggers the error path in r6ReadRightSideSymbol that was causing +# tokenDelete to be called with NULL pointers + +# Case 1: R6:: followed by something other than R6Class +TestCase1 <- R6::SomethingElse("TestCase1") + +# Case 2: Incomplete R6 namespace reference +TestCase2 <- R6:: + +# Case 3: R6 followed by :: but with syntax error +TestCase3 <- R6::R6Clas("TestCase3") + diff --git a/main/tokeninfo.c b/main/tokeninfo.c index 380811d80a..134af73c2d 100644 --- a/main/tokeninfo.c +++ b/main/tokeninfo.c @@ -91,7 +91,8 @@ void flashTokenBacklog (struct tokenInfoClass *klass) void tokenDelete (tokenInfo *token) { - objPoolPut (token->klass->pool, token); + if (token != NULL) + objPoolPut (token->klass->pool, token); } diff --git a/parsers/r-r6class.c b/parsers/r-r6class.c index e19d1e0ab9..ef7b261d0f 100644 --- a/parsers/r-r6class.c +++ b/parsers/r-r6class.c @@ -219,14 +219,14 @@ static int r6ReadRightSideSymbol (rSubparser *s, tokenInfo * token1 = NULL; if (strcmp (tokenString (token), "R6") == 0) { - tokenInfo * token0 = rNewToken (); + token0 = rNewToken (); tokenRead (token0); if (!tokenIsType (token0, R_SCOPE)) goto reject; if (strcmp (tokenString (token0), "::")) goto reject; - tokenInfo * token1 = rNewToken (); + token1 = rNewToken (); tokenRead (token1); if (!tokenIsType (token1, R_SYMBOL)) goto reject; @@ -252,11 +252,12 @@ static int r6ReadRightSideSymbol (rSubparser *s, } return CORK_NIL; reject: - if (token1) + /* For incomplete "R6::" cases, we don't want to unread the "::" token + as the main R parser may not handle it well. */ + if (token1 && tokenIsType(token1, R_SYMBOL)) { tokenUnread (token1); - if (token0) - tokenUnread (token0); - /* tokenDelete accepts NULL. */ + } + /* Don't unread token0 (::) to prevent main parser confusion */ tokenDelete (token1); tokenDelete (token0);