2525import com .google .common .collect .ImmutableSet ;
2626import com .google .errorprone .annotations .CanIgnoreReturnValue ;
2727import com .google .errorprone .annotations .Immutable ;
28+ import java .util .Set ;
2829import javax .annotation .concurrent .ThreadSafe ;
2930import com .google .protobuf .ByteString ;
3031import com .google .protobuf .NullValue ;
@@ -343,7 +344,13 @@ private IntermediateResult resolveIdent(ExecutionFrame frame, CelExpr expr, Stri
343344 Object value = rawResult .value ();
344345 boolean isLazyExpression = value instanceof LazyExpression ;
345346 if (isLazyExpression ) {
346- value = evalInternal (frame , ((LazyExpression ) value ).celExpr ).value ();
347+ frame .markLazyEvaluationOrThrow (name );
348+
349+ try {
350+ value = evalInternal (frame , ((LazyExpression ) value ).celExpr ).value ();
351+ } finally {
352+ frame .endLazyEvaluation (name );
353+ }
347354 }
348355
349356 // Value resolved from Binding, it could be Message, PartialMessage or unbound(null)
@@ -1065,7 +1072,11 @@ private IntermediateResult evalCelBlock(
10651072 }
10661073 frame .pushLazyScope (Collections .unmodifiableMap (blockList ));
10671074
1068- return evalInternal (frame , blockCall .args ().get (1 ));
1075+ try {
1076+ return evalInternal (frame , blockCall .args ().get (1 ));
1077+ } finally {
1078+ frame .popScope ();
1079+ }
10691080 }
10701081
10711082 private CelType getCheckedTypeOrThrow (CelExpr expr ) throws CelEvaluationException {
@@ -1115,6 +1126,7 @@ static class ExecutionFrame {
11151126 private final int maxIterations ;
11161127 private final ArrayDeque <RuntimeUnknownResolver > resolvers ;
11171128 private final Optional <? extends CelFunctionResolver > lateBoundFunctionResolver ;
1129+ private final Set <String > activeLazyAttributes = new HashSet <>();
11181130 private RuntimeUnknownResolver currentResolver ;
11191131 private int iterations ;
11201132 @ VisibleForTesting int scopeLevel ;
@@ -1132,6 +1144,17 @@ private ExecutionFrame(
11321144 this .maxIterations = maxIterations ;
11331145 }
11341146
1147+ private void markLazyEvaluationOrThrow (String name ) {
1148+ boolean added = activeLazyAttributes .add (name );
1149+ if (!added ) {
1150+ throw new IllegalStateException (String .format ("Cycle detected: %s" , name ));
1151+ }
1152+ }
1153+
1154+ private void endLazyEvaluation (String name ) {
1155+ activeLazyAttributes .remove (name );
1156+ }
1157+
11351158 private Optional <CelEvaluationListener > getEvaluationListener () {
11361159 return evaluationListener ;
11371160 }
0 commit comments