Skip to content

Commit 902b969

Browse files
l46kokcopybara-github
authored andcommitted
Fix overflow handlings for Uint, add more test cases around IntSort overflows
PiperOrigin-RevId: 952879660
1 parent c97a361 commit 902b969

2 files changed

Lines changed: 53 additions & 6 deletions

File tree

verifier/src/main/java/dev/cel/verifier/CelZ3TypeSystem.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import com.google.common.collect.Lists;
1818
import com.google.common.collect.ObjectArrays;
19+
import com.google.common.primitives.UnsignedLongs;
1920
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2021
import com.microsoft.z3.ArithExpr;
2122
import com.microsoft.z3.ArrayExpr;
@@ -300,9 +301,14 @@ public Expr<?> mkInt(long val) {
300301
return ctx.mkApp(intCons.ConstructorDecl(), ctx.mkInt(val));
301302
}
302303

304+
/** Creates a CelValue containing an unsigned integer from a string representation. */
305+
public Expr<?> mkUint(String val) {
306+
return ctx.mkApp(uintCons.ConstructorDecl(), ctx.mkInt(val));
307+
}
308+
303309
/** Creates a CelValue containing an unsigned integer. */
304310
public Expr<?> mkUint(long val) {
305-
return ctx.mkApp(uintCons.ConstructorDecl(), ctx.mkInt(val));
311+
return mkUint(UnsignedLongs.toString(val));
306312
}
307313

308314
/** Creates a CelValue containing a double. */
@@ -859,10 +865,8 @@ public static BoolExpr mkNotFlattened(Context ctx, BoolExpr arg) {
859865
this.boolCons =
860866
ctx.mkConstructor(
861867
CONS_BOOL, IS_BOOL, new String[] {GET_BOOL}, new Sort[] {ctx.getBoolSort()}, null);
862-
// Note: Z3's IntSort models unbounded mathematical integers. We do not currently use
863-
// BitVecSort(64), which means CEL integer overflow semantics are not natively modeled,
864-
// and bitwise operations are unsupported. We enforce 64-bit value bounds explicitly
865-
// during variable constraint generation instead.
868+
// We use Z3's IntSort instead of BitVecSort(64) for faster arithmetic solving without
869+
// bit-blasting, explicitly enforcing 64-bit range bounds and overflow errors.
866870
this.intCons =
867871
ctx.mkConstructor(
868872
CONS_INT, IS_INT, new String[] {GET_INT}, new Sort[] {ctx.getIntSort()}, null);

verifier/src/test/java/dev/cel/verifier/CelVerifierZ3ImplTest.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ public final class CelVerifierZ3ImplTest {
8484
.addMessageTypes(TestAllTypes.getDescriptor(), TestAllTypes.NestedMessage.getDescriptor())
8585
.addVar("x", SimpleType.INT)
8686
.addVar("u", SimpleType.UINT)
87+
.addVar("u1", SimpleType.UINT)
88+
.addVar("u2", SimpleType.UINT)
8789
.addVar("d", SimpleType.DOUBLE)
8890
.addVar("by", SimpleType.BYTES)
8991
.addVar("y", SimpleType.INT)
@@ -705,6 +707,10 @@ private enum IsAlwaysTrueTestCase {
705707
DYNAMIC_NUMERIC_EQUALITY_CROSS_TYPE_DYN_DOUBLE(
706708
"type(dyn_var) == double && dyn_var == 5.0 && dyn_var2 == 5.0 && type(dyn_var2) == double ?"
707709
+ " dyn_var == dyn_var2 : true"),
710+
INT64_BOUNDS_ALWAYS_TRUE("x <= 9223372036854775807 && x >= -9223372036854775808"),
711+
UINT64_BOUNDS_ALWAYS_TRUE("u <= 18446744073709551615u && u >= 0u"),
712+
MODULO_INT64_MIN_INT_BY_NEG_ONE_ALWAYS_ZERO(
713+
"x == -9223372036854775808 && y == -1 ? x % y == 0 : true"),
708714
;
709715

710716
final String expr;
@@ -1203,7 +1209,44 @@ private enum IsAlwaysTrueViolationTestCase {
12031209
"type(dyn_var) == int ? (dyn_var ? true : false) == (dyn_var ? true : false) : true",
12041210
"Condition is not always true\\.",
12051211
"Counterexample input:",
1206-
"dyn_var = int\\{\\}");
1212+
"dyn_var = int\\{\\}"),
1213+
ADD_INT64_OVERFLOW_FAILS_WITH_ERRORS(
1214+
"x > 0 && y > 0 ? x + y > x : true",
1215+
"Condition is not always true\\.",
1216+
"Counterexample input:",
1217+
"x = (1|9223372036854775807)",
1218+
"y = (1|9223372036854775807)"),
1219+
ADD_UINT64_OVERFLOW_FAILS_WITH_ERRORS(
1220+
"u1 > 0u && u2 > 0u ? u1 + u2 >= u1 : true",
1221+
"Condition is not always true\\.",
1222+
"Counterexample input:",
1223+
"u1 = (1u|18446744073709551615u)",
1224+
"u2 = (1u|18446744073709551615u)"),
1225+
SUBTRACT_INT64_UNDERFLOW_FAILS_WITH_ERRORS(
1226+
"x < 0 && y > 0 ? x - y < x : true",
1227+
"Condition is not always true\\.",
1228+
"Counterexample input:",
1229+
"x = (-2|9223372036854775807)",
1230+
"y = (-2|9223372036854775807)"),
1231+
MULTIPLY_INT64_OVERFLOW_FAILS_WITH_ERRORS(
1232+
"x > 1000000000 && y > 1000000000 ? x * y > 0 : true",
1233+
"Condition is not always true\\.",
1234+
"Counterexample input:",
1235+
"x = [0-9]+",
1236+
"y = [0-9]+"),
1237+
MULTIPLY_UINT64_OVERFLOW_FAILS_WITH_ERRORS(
1238+
"u1 > 1000000000u && u2 > 1000000000u ? u1 * u2 > 0u : true",
1239+
"Condition is not always true\\.",
1240+
"Counterexample input:",
1241+
"u1 = [0-9]+u",
1242+
"u2 = [0-9]+u"),
1243+
DIVIDE_INT64_OVERFLOW_MIN_INT_BY_NEG_ONE_FAILS_WITH_ERRORS(
1244+
"x == -9223372036854775808 && y == -1 ? x / y == -x : true",
1245+
"Condition is not always true\\.",
1246+
"Counterexample input:",
1247+
"x = -9223372036854775808",
1248+
"y = -1"),
1249+
;
12071250

12081251
final String expr;
12091252
final ImmutableList<String> expectedFragments;

0 commit comments

Comments
 (0)