1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-01 13:41:34 +00:00

Fixed code that caused a seg-fault after parsing a (deferred) post-count argument followed by a (nested) function-call argument.

The old broken code defers the count until the end of the (parent function's) argument list.  But, a nested function call clears the pointer to the deferred type.  That leads to an access violation.
The new code defers only until the end of each argument.  Fixes #1320.
This commit is contained in:
Greg King 2020-11-20 17:29:26 -05:00
parent 79bdc2d51f
commit 8b42f570e9
3 changed files with 34 additions and 37 deletions

View File

@ -1,7 +1,7 @@
/* expr.c /* expr.c
** **
** 1998-06-21, Ullrich von Bassewitz ** 1998-06-21, Ullrich von Bassewitz
** 2020-01-25, Greg King ** 2020-11-20, Greg King
*/ */
@ -608,6 +608,8 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall, ExprDesc* ED)
** The function returns the size of the arguments pushed in bytes. ** The function returns the size of the arguments pushed in bytes.
*/ */
{ {
ExprDesc Expr;
/* Initialize variables */ /* Initialize variables */
SymEntry* Param = 0; /* Keep gcc silent */ SymEntry* Param = 0; /* Keep gcc silent */
unsigned PushedSize = 0; /* Size of arguments pushed */ unsigned PushedSize = 0; /* Size of arguments pushed */
@ -634,7 +636,6 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall, ExprDesc* ED)
** **
*/ */
if (ParamComplete && IS_Get (&CodeSizeFactor) >= 200) { if (ParamComplete && IS_Get (&CodeSizeFactor) >= 200) {
/* Calculate the number and size of the parameters */ /* Calculate the number and size of the parameters */
FrameParams = Func->ParamCount; FrameParams = Func->ParamCount;
FrameSize = Func->ParamSize; FrameSize = Func->ParamSize;
@ -656,18 +657,13 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall, ExprDesc* ED)
} }
} }
/* The info of the last argument could be needed out of the loop */
ExprDesc Expr;
ED_Init (&Expr);
Expr.Flags |= ED->Flags & E_MASK_KEEP_SUBEXPR;
/* Parse the actual argument list */ /* Parse the actual argument list */
while (CurTok.Tok != TOK_RPAREN) { while (CurTok.Tok != TOK_RPAREN) {
unsigned Flags; /* Code generator flags, not expression flags */ unsigned Flags; /* Code generator flags, not expression flags */
/* This way the info of the last parameter won't be cleared */
ED_Init (&Expr); ED_Init (&Expr);
/* This way, the info of the last parameter won't be cleared */
Expr.Flags |= ED->Flags & E_MASK_KEEP_SUBEXPR; Expr.Flags |= ED->Flags & E_MASK_KEEP_SUBEXPR;
/* Count arguments */ /* Count arguments */
@ -781,18 +777,20 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall, ExprDesc* ED)
Error ("Argument expected after comma"); Error ("Argument expected after comma");
break; break;
} }
DoDeferred (SQP_KEEP_NONE, &Expr);
} }
/* Append last deferred inc/dec before the function is called.
** The last parameter needs to be preserved if it is passed in AX/EAX Regs.
*/
DoDeferred (IsFastcall ? SQP_KEEP_EAX : SQP_KEEP_NONE, &Expr);
/* Check if we had enough arguments */ /* Check if we had enough arguments */
if (PushedCount < Func->ParamCount) { if (PushedCount < Func->ParamCount) {
Error ("Too few arguments in function call"); Error ("Too few arguments in function call");
} }
/* Append deferred inc/dec before the function is called.
** The last parameter needs to be restored if it is passed with AX/EAX Regs.
*/
DoDeferred (IsFastcall ? SQP_KEEP_EAX : SQP_KEEP_NONE, &Expr);
/* The function returns the size of all arguments pushed onto the stack. /* The function returns the size of all arguments pushed onto the stack.
** However, if there are parameters missed (which is an error, and was ** However, if there are parameters missed (which is an error, and was
** flagged by the compiler), AND a stack frame was preallocated above, ** flagged by the compiler), AND a stack frame was preallocated above,
@ -1395,7 +1393,7 @@ static void ArrayRef (ExprDesc* Expr)
/* The array subscript is a constant. Since we can have the element /* The array subscript is a constant. Since we can have the element
** address directly as base+offset, we can remove the array address ** address directly as base+offset, we can remove the array address
** push onto the stack before if loading subscript doesn't tamper that ** push onto the stack before if loading subscript doesn't tamper that
** address in the primary. ** address in the primary.
*/ */
if (!ConstBaseAddr) { if (!ConstBaseAddr) {
RemoveCode (&Mark2); RemoveCode (&Mark2);
@ -1419,7 +1417,7 @@ static void ArrayRef (ExprDesc* Expr)
** remove the code that loaded the address into the primary. ** remove the code that loaded the address into the primary.
*/ */
if (!IsTypeArray (Expr->Type)) { if (!IsTypeArray (Expr->Type)) {
/* It's a pointer, so we do have to load it into the primary /* It's a pointer, so we do have to load it into the primary
** first (if it's not already there). ** first (if it's not already there).
*/ */
@ -2025,8 +2023,8 @@ static void PostInc (ExprDesc* Expr)
/* Get the data type */ /* Get the data type */
Flags = TypeOf (Expr->Type); Flags = TypeOf (Expr->Type);
/* We are allowed by the C standard to defer the inc operation until /* We are allowed by the C standard to defer the inc operation until after
** the this expression is used, so that we don't need to save and reload ** the expression is used, so that we don't need to save and reload
** the original value. ** the original value.
*/ */
@ -2065,7 +2063,7 @@ static void PostInc (ExprDesc* Expr)
/* Fetch the value and use it (since it's the result of the expression) */ /* Fetch the value and use it (since it's the result of the expression) */
LoadExpr (CF_NONE, Expr); LoadExpr (CF_NONE, Expr);
/* Defer the increment until the value of this expression is used */; /* Defer the increment until after the value of this expression is used */
DeferInc (Expr); DeferInc (Expr);
} }
} }
@ -2132,7 +2130,7 @@ static void PostDec (ExprDesc* Expr)
/* Fetch the value and save it (since it's the result of the expression) */ /* Fetch the value and save it (since it's the result of the expression) */
LoadExpr (CF_NONE, Expr); LoadExpr (CF_NONE, Expr);
/* Defer the decrement until the value of this expression is used */; /* Defer the decrement until after the value of this expression is used */
DeferDec (Expr); DeferDec (Expr);
} }
} }
@ -3738,7 +3736,7 @@ static void hieOr (ExprDesc *Expr)
Error ("Scalar expression expected"); Error ("Scalar expression expected");
ED_MakeConstBool (Expr, 0); ED_MakeConstBool (Expr, 0);
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { } else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
if (!ED_IsConstBool (Expr)) { if (!ED_IsConstBool (Expr)) {
/* Test the lhs if we haven't had && operators. If we had them, the /* Test the lhs if we haven't had && operators. If we had them, the
** jump is already in place and there's no need to do the test. ** jump is already in place and there's no need to do the test.
@ -3749,7 +3747,7 @@ static void hieOr (ExprDesc *Expr)
/* Get first expr */ /* Get first expr */
LoadExpr (CF_FORCECHAR, Expr); LoadExpr (CF_FORCECHAR, Expr);
/* Append deferred inc/dec at sequence point */ /* Append deferred inc/dec at sequence point */
DoDeferred (SQP_KEEP_TEST, Expr); DoDeferred (SQP_KEEP_TEST, Expr);

View File

@ -100,12 +100,6 @@ $(WORKDIR)/bug1263.$1.$2.prg: bug1263.c | $(WORKDIR)
$(if $(QUIET),echo misc/bug1263.$1.$2.prg) $(if $(QUIET),echo misc/bug1263.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR) $(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should compile, but gives an error (segfault)
$(WORKDIR)/bug1320.$1.$2.prg: bug1320.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile."
$(if $(QUIET),echo misc/bug1320.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# this one requires --std=c89, it fails with --std=c99 # this one requires --std=c89, it fails with --std=c99
# it fails currently at runtime # it fails currently at runtime
$(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR) $(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR)
@ -114,7 +108,7 @@ $(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR)
$(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR) $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR)
$(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
$(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR) $(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR)
# should compile, but then hangs in an endless loop # should compile, but then hangs in an endless loop
$(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR) $(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR)
$(if $(QUIET),echo misc/endless.$1.$2.prg) $(if $(QUIET),echo misc/endless.$1.$2.prg)
@ -130,7 +124,7 @@ $(WORKDIR)/bug1348.$1.$2.prg: bug1348.c | $(WORKDIR)
$(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR) $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR)
$(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
$(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR) $(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR)
# these need reference data that can't be generated by a host-compiled program, # these need reference data that can't be generated by a host-compiled program,
# in a useful way # in a useful way
$(WORKDIR)/limits.$1.$2.prg: limits.c $(ISEQUAL) | $(WORKDIR) $(WORKDIR)/limits.$1.$2.prg: limits.c $(ISEQUAL) | $(WORKDIR)

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 The cc65 Authors Copyright 2020, The cc65 Authors
This software is provided "as-is", without any express or implied This software is provided "as-is", without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@ -21,18 +21,23 @@
/* /*
Test of a post-counted pointer argument, Test of a post-counted pointer argument,
followed by a (nested) function-call argument. followed by a (nested) function-call argument.
Test that compiling it doesn't cause a seg-fault.
https://github.com/cc65/cc65/issues/1320 https://github.com/cc65/cc65/issues/1320
After the bug is fixed, this file should be moved to "test/val/".
*/ */
static char *var; static char *var;
void foo (char *, char); static void foo (char *, char)
char bar (void); {
}
void main (void) static char bar (void)
{
return 'b';
}
int main (void)
{ {
foo (var++, bar ()); foo (var++, bar ());
return 0; return 0;