Skip to content

Commit 98bd0d7

Browse files
l46kokcopybara-github
authored andcommitted
Fix soundness issues for comprehensions beyond BMC unroll limit
PiperOrigin-RevId: 987896182
1 parent a07c04b commit 98bd0d7

7 files changed

Lines changed: 537 additions & 401 deletions

File tree

‎verifier/src/main/java/dev/cel/verifier/BUILD.bazel‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ java_library(
118118
],
119119
deps = [
120120
":numeric_bounds",
121+
"//:auto_value",
121122
"//common/internal:proto_time_utils",
122123
"@maven//:com_google_errorprone_error_prone_annotations",
123124
"@maven//:com_google_guava_guava",

‎verifier/src/main/java/dev/cel/verifier/CelAstToZ3Translator.java‎

Lines changed: 146 additions & 171 deletions
Large diffs are not rendered by default.

‎verifier/src/main/java/dev/cel/verifier/CelVerifierZ3Impl.java‎

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414

1515
package dev.cel.verifier;
1616

17+
import static com.google.common.base.Preconditions.checkArgument;
18+
import static com.google.common.base.Preconditions.checkNotNull;
19+
1720
import com.google.common.annotations.VisibleForTesting;
18-
import com.google.common.base.Preconditions;
1921
import com.google.common.collect.ImmutableList;
2022
import com.google.common.collect.ImmutableMap;
2123
import com.google.common.collect.ImmutableSet;
@@ -38,9 +40,7 @@
3840
import dev.cel.verifier.axioms.CelZ3FunctionAxiom;
3941
import dev.cel.verifier.axioms.CelZ3StandardAxioms;
4042
import java.time.Duration;
41-
import java.util.ArrayList;
4243
import java.util.Arrays;
43-
import java.util.List;
4444
import java.util.Locale;
4545
import java.util.Map;
4646
import java.util.Optional;
@@ -78,7 +78,7 @@ static Builder newBuilder() {
7878
}
7979

8080
static Builder newBuilder(Cel cel) {
81-
return new Builder(Preconditions.checkNotNull(cel));
81+
return new Builder(checkNotNull(cel));
8282
}
8383

8484
static final class Builder implements CelVerifierBuilder {
@@ -89,15 +89,6 @@ static final class Builder implements CelVerifierBuilder {
8989
private final Cel cel;
9090
private CelTypeProvider typeProvider;
9191

92-
private Builder(Cel cel) {
93-
this.timeout = Duration.ofSeconds(10);
94-
this.comprehensionUnrollLimit = 5;
95-
this.unknownIdentifiers = ImmutableSet.builder();
96-
this.functionAxioms = ImmutableList.builder();
97-
this.typeProvider = EMPTY_TYPE_PROVIDER;
98-
this.cel = cel;
99-
}
100-
10192
@Override
10293
@CanIgnoreReturnValue
10394
public Builder setTimeout(Duration timeout) {
@@ -118,14 +109,14 @@ public CelVerifierBuilder addUnknownIdentifier(String identifier) {
118109
@Override
119110
@CanIgnoreReturnValue
120111
public CelVerifierBuilder setTypeProvider(CelTypeProvider typeProvider) {
121-
this.typeProvider = Preconditions.checkNotNull(typeProvider);
112+
this.typeProvider = checkNotNull(typeProvider);
122113
return this;
123114
}
124115

125116
@Override
126117
@CanIgnoreReturnValue
127118
public CelVerifierBuilder setComprehensionUnrollLimit(int unrollLimit) {
128-
Preconditions.checkArgument(unrollLimit >= 0, "unrollLimit must be non-negative");
119+
checkArgument(unrollLimit >= 0, "unrollLimit must be non-negative");
129120
this.comprehensionUnrollLimit = unrollLimit;
130121
return this;
131122
}
@@ -158,27 +149,36 @@ public CelVerifier build() {
158149
typeProvider,
159150
cel);
160151
}
152+
153+
private Builder(Cel cel) {
154+
this.timeout = Duration.ofSeconds(10);
155+
this.comprehensionUnrollLimit = 5;
156+
this.unknownIdentifiers = ImmutableSet.builder();
157+
this.functionAxioms = ImmutableList.builder();
158+
this.typeProvider = EMPTY_TYPE_PROVIDER;
159+
this.cel = cel;
160+
}
161161
}
162162

163163
@Override
164164
public CelVerificationResult isSatisfiable(CelAbstractSyntaxTree ast)
165165
throws CelVerificationException {
166-
Preconditions.checkArgument(ast.isChecked(), "AST must be type-checked.");
166+
checkArgument(ast.isChecked(), "AST must be type-checked.");
167167
return checkSatisfiability(ast, /* searchForCounterexample= */ false);
168168
}
169169

170170
@Override
171171
public CelVerificationResult isAlwaysTrue(CelAbstractSyntaxTree ast)
172172
throws CelVerificationException {
173-
Preconditions.checkArgument(ast.isChecked(), "AST must be type-checked.");
173+
checkArgument(ast.isChecked(), "AST must be type-checked.");
174174
return checkSatisfiability(ast, /* searchForCounterexample= */ true);
175175
}
176176

177177
@Override
178178
public CelVerificationResult verifyEquivalence(
179179
CelAbstractSyntaxTree astA, CelAbstractSyntaxTree astB) throws CelVerificationException {
180-
Preconditions.checkArgument(astA.isChecked(), "astA must be type-checked.");
181-
Preconditions.checkArgument(astB.isChecked(), "astB must be type-checked.");
180+
checkArgument(astA.isChecked(), "astA must be type-checked.");
181+
checkArgument(astB.isChecked(), "astB must be type-checked.");
182182
CelOptimizer optimizer =
183183
CelOptimizerFactory.standardCelOptimizerBuilder(cel)
184184
.addAstOptimizers(
@@ -195,6 +195,7 @@ public CelVerificationResult verifyEquivalence(
195195
CelAstToZ3Translator translator =
196196
new CelAstToZ3Translator(
197197
ctx, comprehensionUnrollLimit, unknownIdentifiers, functionRegistry, typeProvider);
198+
translator.getTypeSystem().enableParameterizedUnknownPropagation();
198199

199200
TranslatedValue tvA = translator.translate(astA);
200201
TranslatedValue tvB = translator.translate(astB);
@@ -262,10 +263,10 @@ CelVerificationResult verifyImplication(
262263
Map<String, CelAbstractSyntaxTree> boundSymbols,
263264
String subjectName)
264265
throws CelVerificationException {
265-
Preconditions.checkArgument(assumeAst.isChecked(), "assumeAst must be type-checked.");
266-
Preconditions.checkArgument(assertAst.isChecked(), "assertAst must be type-checked.");
266+
checkArgument(assumeAst.isChecked(), "assumeAst must be type-checked.");
267+
checkArgument(assertAst.isChecked(), "assertAst must be type-checked.");
267268
for (Map.Entry<String, CelAbstractSyntaxTree> entry : boundSymbols.entrySet()) {
268-
Preconditions.checkArgument(
269+
checkArgument(
269270
entry.getValue().isChecked(),
270271
"boundSymbol AST for '%s' must be type-checked.",
271272
entry.getKey());
@@ -276,22 +277,20 @@ CelVerificationResult verifyImplication(
276277
new CelAstToZ3Translator(
277278
ctx, comprehensionUnrollLimit, unknownIdentifiers, functionRegistry, typeProvider);
278279

279-
List<BoolExpr> taints = new ArrayList<>();
280280
for (Map.Entry<String, CelAbstractSyntaxTree> entry : boundSymbols.entrySet()) {
281281
TranslatedValue tv = translator.translate(entry.getValue());
282282
translator.bindSymbol(entry.getKey(), tv);
283283
}
284284

285285
TranslatedValue assumeTv = translator.translate(assumeAst);
286286
TranslatedValue assertTv = translator.translate(assertAst);
287-
taints.add(assumeTv.isApproximate());
288-
taints.add(assertTv.isApproximate());
289287

290288
BoolExpr assumeCondition = translator.isTrue(assumeTv.z3Expr());
291289
BoolExpr assertCondition = translator.isTrue(assertTv.z3Expr());
292290
BoolExpr violationCondition = ctx.mkAnd(assumeCondition, ctx.mkNot(assertCondition));
293291

294-
BoolExpr combinedTaint = CelZ3TypeSystem.mkOrFlattened(ctx, taints);
292+
BoolExpr combinedTaint =
293+
CelZ3TypeSystem.mkOrFlattened(ctx, assumeTv.isApproximate(), assertTv.isApproximate());
295294
BoolExpr unknownCondition =
296295
ctx.mkOr(
297296
translator.getTypeSystem().isUnknown(assumeTv.z3Expr()),
@@ -513,21 +512,6 @@ private static String getCounterexampleString(
513512
ctx, typeSystem, model, isApproximate, isCounterexample);
514513
}
515514

516-
CelVerifierZ3Impl(
517-
Duration timeout,
518-
int comprehensionUnrollLimit,
519-
ImmutableSet<String> unknownIdentifiers,
520-
CelZ3FunctionRegistry functionRegistry,
521-
CelTypeProvider typeProvider,
522-
Cel cel) {
523-
this.timeout = timeout;
524-
this.comprehensionUnrollLimit = comprehensionUnrollLimit;
525-
this.unknownIdentifiers = unknownIdentifiers;
526-
this.functionRegistry = functionRegistry;
527-
this.typeProvider = typeProvider;
528-
this.cel = cel;
529-
}
530-
531515
private enum SolverOutcome {
532516
EXACT_MATCH,
533517
APPROXIMATE_MATCH,
@@ -537,9 +521,9 @@ private enum SolverOutcome {
537521
}
538522

539523
private static final class SolverRunResult {
540-
final SolverOutcome outcome;
541-
final @Nullable Model model;
542-
final @Nullable String reason;
524+
private final SolverOutcome outcome;
525+
private final @Nullable Model model;
526+
private final @Nullable String reason;
543527

544528
static SolverRunResult exactMatch(Model model) {
545529
return new SolverRunResult(SolverOutcome.EXACT_MATCH, model, null);
@@ -567,4 +551,19 @@ private SolverRunResult(SolverOutcome outcome, @Nullable Model model, @Nullable
567551
this.reason = reason;
568552
}
569553
}
554+
555+
private CelVerifierZ3Impl(
556+
Duration timeout,
557+
int comprehensionUnrollLimit,
558+
ImmutableSet<String> unknownIdentifiers,
559+
CelZ3FunctionRegistry functionRegistry,
560+
CelTypeProvider typeProvider,
561+
Cel cel) {
562+
this.timeout = timeout;
563+
this.comprehensionUnrollLimit = comprehensionUnrollLimit;
564+
this.unknownIdentifiers = unknownIdentifiers;
565+
this.functionRegistry = functionRegistry;
566+
this.typeProvider = typeProvider;
567+
this.cel = cel;
568+
}
570569
}

0 commit comments

Comments
 (0)