Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a crash when using a constant global variable (created via MakeConstantGlobal, such as IsHPCGAP) as index variable of a for loop #3808

Merged
merged 2 commits into from
Dec 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions src/code.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,12 +1086,6 @@ void CodeForBegin ( void )

void CodeForIn ( void )
{
Expr var = PopExpr();
if (TNUM_EXPR(var) == EXPR_REF_GVAR)
{
PushGlobalForLoopVariable(READ_EXPR(var, 0));
}
PushExpr(var);
}

void CodeForBeginBody ( void )
Expand All @@ -1112,9 +1106,6 @@ void CodeForEndBody (
/* get the variable reference */
var = PopExpr();

if (TNUM_EXPR(var) == EXPR_REF_GVAR)
PopGlobalForLoopVariable();

/* select the type of the for-statement */
if ( TNUM_EXPR(list) == EXPR_RANGE && SIZE_EXPR(list) == 2*sizeof(Expr)
&& IS_REF_LVAR(var) ) {
Expand Down
23 changes: 15 additions & 8 deletions src/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,28 +105,29 @@ static void ReadFuncExprAbbrevSingle(ScannerState * s, TypSymbolSet follow);

static void ReadAtom(ScannerState * s, TypSymbolSet follow, Char mode);

void PushGlobalForLoopVariable( UInt var)
static void PushGlobalForLoopVariable(UInt var)
{
struct ReaderState * rs = ReaderState();
if (rs->CurrentGlobalForLoopDepth < 100)
if (rs->CurrentGlobalForLoopDepth <
ARRAY_SIZE(rs->CurrentGlobalForLoopVariables))
rs->CurrentGlobalForLoopVariables[rs->CurrentGlobalForLoopDepth] = var;
rs->CurrentGlobalForLoopDepth++;
}

void PopGlobalForLoopVariable( void )
static void PopGlobalForLoopVariable(void)
{
GAP_ASSERT(ReaderState()->CurrentGlobalForLoopDepth);
ReaderState()->CurrentGlobalForLoopDepth--;
}

static UInt GlobalComesFromEnclosingForLoop (UInt var)
static UInt GlobalComesFromEnclosingForLoop(UInt var)
{
struct ReaderState * rs = ReaderState();
for (UInt i = 0; i < rs->CurrentGlobalForLoopDepth; i++) {
if (i == 100)
return 0;
if (i == ARRAY_SIZE(rs->CurrentGlobalForLoopVariables))
return 0;
if (rs->CurrentGlobalForLoopVariables[i] == var)
return 1;
return 1;
}
return 0;
}
Expand Down Expand Up @@ -2050,7 +2051,9 @@ static void ReadFor(ScannerState * s, TypSymbolSet follow)
Match(s, S_FOR, "for", follow);

/* <Var> */
ReadCallVarAss(s, follow, 'r');
volatile LHSRef ref = ReadVar(s, follow);
if (ref.type != R_INVALID)
EvalRef(ref, 1);

/* 'in' <Expr> */
Match(s, S_IN, "in", S_DO|S_OD|follow);
Expand All @@ -2059,11 +2062,15 @@ static void ReadFor(ScannerState * s, TypSymbolSet follow)

/* 'do' <Statements> */
Match(s, S_DO, "do", STATBEGIN|S_OD|follow);
if (ref.type == R_GVAR)
PushGlobalForLoopVariable(ref.var);
ReaderState()->LoopNesting++;
TRY_IF_NO_ERROR { IntrForBeginBody(); }
nrs = ReadStats(s, S_OD|follow);
TRY_IF_NO_ERROR { IntrForEndBody( nrs ); }
ReaderState()->LoopNesting--;
if (ref.type == R_GVAR)
PopGlobalForLoopVariable();

/* 'od' */
Match(s, S_OD, "while parsing a 'for' loop: statement or 'od'", follow);
Expand Down
8 changes: 0 additions & 8 deletions src/read.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,6 @@ void StartFakeFuncExpr(Int startLine);
void FinishAndCallFakeFuncExpr(void);


/****************************************************************************
**
*/
void PushGlobalForLoopVariable(UInt var);

void PopGlobalForLoopVariable(void);


/****************************************************************************
**
*F Call0ArgsInNewReader(Obj f) . . . . . . . . . . . . call a GAP function
Expand Down
36 changes: 36 additions & 0 deletions tst/testinstall/coder.tst
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,41 @@ gap> function() Unbind(l![fail]); end();
Error, PosObj Assignment: <position> must be a positive small integer (not the\
value 'fail')

#
# weird corner cases in for loop index variables
#
gap> function() for + in [1,2,3] do od; end();
Syntax error: Identifier expected in stream:1
function() for + in [1,2,3] do od; end();
^
gap> function() local x; for x[1] in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() local x; for x[1] in [1,2,3] do od; end();
^
gap> function() local x; for x{[1]} in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() local x; for x{[1]} in [1,2,3] do od; end();
^
gap> function() for IsHPCGAP in [1,2,3] do od; end();
Error, Variable: 'IsHPCGAP' is constant
gap> function() for IsHPCGAP[1] in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for IsHPCGAP[1] in [1,2,3] do od; end();
^
gap> function() for IsHPCGAP{[1]} in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for IsHPCGAP{[1]} in [1,2,3] do od; end();
^
gap> function() for PrintObj in [1,2,3] do od; end();
Error, Variable: 'PrintObj' is read only
gap> function() for PrintObj[1] in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for PrintObj[1] in [1,2,3] do od; end();
^
gap> function() for PrintObj{[1]} in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for PrintObj{[1]} in [1,2,3] do od; end();
^

#
gap> STOP_TEST("coder.tst", 1);
36 changes: 36 additions & 0 deletions tst/testinstall/interpreter.tst
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,42 @@ gap> Unbind(l![fail]);
Error, PosObj Assignment: <position> must be a positive small integer (not the\
value 'fail')

#
# weird corner cases in for loop index variables
#
gap> for + in [1,2,3] do od;
Syntax error: Identifier expected in stream:1
for + in [1,2,3] do od;
^
gap> for x[1] in [1,2,3] do od;
Syntax error: in expected in stream:1
for x[1] in [1,2,3] do od;
^
gap> for x{[1]} in [1,2,3] do od;
Syntax error: in expected in stream:1
for x{[1]} in [1,2,3] do od;
^
gap> for IsHPCGAP in [1,2,3] do od;
Error, Variable: 'IsHPCGAP' is constant
gap> for IsHPCGAP[1] in [1,2,3] do od;
Syntax error: in expected in stream:1
for IsHPCGAP[1] in [1,2,3] do od;
^
gap> for IsHPCGAP{[1]} in [1,2,3] do od;
Syntax error: in expected in stream:1
for IsHPCGAP{[1]} in [1,2,3] do od;
^
gap> for PrintObj in [1,2,3] do od;
Error, Variable: 'PrintObj' is read only
gap> for PrintObj[1] in [1,2,3] do od;
Syntax error: in expected in stream:1
for PrintObj[1] in [1,2,3] do od;
^
gap> for PrintObj{[1]} in [1,2,3] do od;
Syntax error: in expected in stream:1
for PrintObj{[1]} in [1,2,3] do od;
^

#
#
gap> STOP_TEST("interpreter.tst", 1);