@@ -568,6 +568,50 @@ func TestAggregateBuiltinArgumentsAreChecked(t *testing.T) {
568568 requireErrorContains (t , err , "memory quota exceeded" )
569569}
570570
571+ func TestCallArgumentMemoryChecksFailFastBeforeLaterSideEffects (t * testing.T ) {
572+ pos := Position {Line : 1 , Column : 1 }
573+ payload := strings .Repeat ("a" , 5000 )
574+ tickCount := 0
575+
576+ stmt := & ExprStmt {
577+ Expr : & CallExpr {
578+ Callee : & Identifier {Name : "noop" , position : pos },
579+ Args : []Expression {
580+ & StringLiteral {Value : payload , position : pos },
581+ & CallExpr {
582+ Callee : & Identifier {Name : "tick" , position : pos },
583+ position : pos ,
584+ },
585+ },
586+ position : pos ,
587+ },
588+ position : pos ,
589+ }
590+
591+ exec := & Execution {
592+ quota : 10000 ,
593+ memoryQuota : 2048 ,
594+ moduleLoading : make (map [string ]bool ),
595+ }
596+ env := newEnv (nil )
597+ env .Define ("noop" , NewBuiltin ("noop" , func (exec * Execution , receiver Value , args []Value , kwargs map [string ]Value , block Value ) (Value , error ) {
598+ return NewNil (), nil
599+ }))
600+ env .Define ("tick" , NewBuiltin ("tick" , func (exec * Execution , receiver Value , args []Value , kwargs map [string ]Value , block Value ) (Value , error ) {
601+ tickCount ++
602+ return NewInt (1 ), nil
603+ }))
604+
605+ _ , _ , err := exec .evalStatements ([]Statement {stmt }, env )
606+ if err == nil {
607+ t .Fatalf ("expected memory quota error for oversized first argument" )
608+ }
609+ requireErrorContains (t , err , "memory quota exceeded" )
610+ if tickCount != 0 {
611+ t .Fatalf ("expected later argument side effects to be skipped, got %d" , tickCount )
612+ }
613+ }
614+
571615func TestTransientAssignmentValueIsCheckedBeforeAssign (t * testing.T ) {
572616 pos := Position {Line : 1 , Column : 1 }
573617 elements := make ([]Expression , 1200 )
0 commit comments