Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions common/src/main/java/dev/cel/common/internal/ProtoAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -325,13 +325,6 @@ private BidiConverter fieldToValueConverter(FieldDescriptor fieldDescriptor) {
value -> BidiConverter.IDENTITY.backwardConverter().convert(maybeUnwrap(value)));
case FLOAT:
return unwrapAndConvert(DOUBLE_CONVERTER);
case DOUBLE:
case SFIXED64:
case SINT64:
case INT64:
return BidiConverter.of(
BidiConverter.IDENTITY.forwardConverter(),
value -> BidiConverter.IDENTITY.backwardConverter().convert(maybeUnwrap(value)));
case BYTES:
if (celOptions.evaluateCanonicalTypesToNativeValues()) {
return BidiConverter.<Object, Object>of(
Expand All @@ -342,21 +335,26 @@ private BidiConverter fieldToValueConverter(FieldDescriptor fieldDescriptor) {
return BidiConverter.of(
BidiConverter.IDENTITY.forwardConverter(),
value -> BidiConverter.IDENTITY.backwardConverter().convert(maybeUnwrap(value)));
case DOUBLE:
case SFIXED64:
case SINT64:
case INT64:
case STRING:
return BidiConverter.of(
BidiConverter.IDENTITY.forwardConverter(),
value -> BidiConverter.IDENTITY.backwardConverter().convert(maybeUnwrap(value)));
case BOOL:
return BidiConverter.of(
BidiConverter.IDENTITY.forwardConverter(),
value -> BidiConverter.IDENTITY.backwardConverter().convert(maybeUnwrap(value)));
case ENUM:
return BidiConverter.<Object, Long>of(
value -> (long) ((EnumValueDescriptor) value).getNumber(),
number ->
fieldDescriptor
.getEnumType()
.findValueByNumberCreatingIfUnknown(number.intValue()));
number -> {
if (number > Integer.MAX_VALUE || number < Integer.MIN_VALUE) {
throw new IllegalArgumentException("Enum value out of int32 range: " + number);
}
return fieldDescriptor
.getEnumType()
.findValueByNumberCreatingIfUnknown(number.intValue());
});
case MESSAGE:
return BidiConverter.<MessageOrBuilder, Object>of(
this::adaptProtoToValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@ public static Duration between(Timestamp from, Timestamp to) {
Instant javaTo = ProtoTimeUtils.toJavaInstant(checkValid(to));

java.time.Duration between = java.time.Duration.between(javaFrom, javaTo);
// Call toNanos() to validate 64-bit nanosecond overflow (throws ArithmeticException).
// Suppress unused variable warning as the duration object itself is returned.
@SuppressWarnings("unused")
long unused = between.toNanos();

return ProtoTimeUtils.toProtoDuration(between);
}
Expand Down
22 changes: 3 additions & 19 deletions conformance/src/test/java/dev/cel/conformance/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,7 @@ _TESTS_TO_SKIP_LEGACY = [
# TODO: Support setting / getting enum values out of the defined enum value range.
"enums/legacy_proto2/select_big,select_neg",
"enums/legacy_proto2/assign_standalone_int_big,assign_standalone_int_neg",
# TODO: Generate errors on enum value assignment overflows for proto3.
"enums/legacy_proto3/assign_standalone_int_too_big,assign_standalone_int_too_neg",
# TODO: Ensure overflow occurs on conversions of double values which might not work properly on all platforms.
"conversions/int/double_int_min_range",
# TODO: Duration and timestamp operations should error on overflow.
"timestamps/timestamp_range/sub_time_duration_over,sub_time_duration_under",

# TODO: Ensure adding negative duration values is appropriately supported.
"timestamps/timestamp_arithmetic/add_time_to_duration_nanos_negative",

Expand Down Expand Up @@ -151,21 +146,10 @@ _TESTS_TO_SKIP_PLANNER = [
"string_ext/format",
"string_ext/format_errors",

# TODO: Check behavior for go/cpp
# TODO: This is actually a user experience degradation.
# Not worth fixing until we see a concrete need.
"basic/functions/unbound_is_runtime_error",

# TODO: Ensure overflow occurs on conversions of double values which might not work properly on all platforms.
"conversions/int/double_int_min_range",
"enums/legacy_proto3/assign_standalone_int_too_big",
"enums/legacy_proto3/assign_standalone_int_too_neg",

# TODO: Duration and timestamp operations should error on overflow.
"timestamps/timestamp_range/sub_time_duration_over",
"timestamps/timestamp_range/sub_time_duration_under",

# Skip until fixed.
"parse/receiver_function_names",

# Type inference edgecases around null(able) assignability.
# These type check, but resolve to a different type.
# list(int), want list(wrapper(int))
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/main/java/dev/cel/runtime/RuntimeHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ public static Optional<UnsignedLong> doubleToUnsignedChecked(double v) {
public static Optional<Long> doubleToLongChecked(double v) {
// getExponent of NaN or Infinite values will return a Double.MAX_EXPONENT + 1 (or 128)
int exp = Math.getExponent(v);
if (exp >= 63 && v != Math.scalb(-1.0, 63)) {
if (exp >= 63) {
return Optional.empty();
}
return Optional.of((long) v);
Expand Down
38 changes: 26 additions & 12 deletions runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package dev.cel.runtime.planner;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.auto.value.AutoValue;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -293,17 +295,24 @@ private PlannedInterpretable planCall(CelExpr expr, PlannerContext ctx) {
}

if (resolvedOverload == null) {
if (!lateBoundFunctionNames.contains(functionName)) {
boolean isLateBound = lateBoundFunctionNames.contains(functionName);
// For type-checked ASTs, functions that are not explicitly registered as late-bound
// must be resolved at plan time.
// For parsed-only ASTs or late-bound functions, defer overload resolution to runtime.
if (ctx.isChecked() && !isLateBound) {
CelReference reference = ctx.referenceMap().get(expr.id());
if (reference != null) {
if (reference != null && !reference.overloadIds().isEmpty()) {
throw new CelOverloadNotFoundException(functionName, reference.overloadIds());
} else {
throw new CelOverloadNotFoundException(functionName);
}
}

ImmutableList<String> overloadIds = ImmutableList.of();
if (resolvedFunction.overloadId().isPresent()) {
CelReference reference = ctx.referenceMap().get(expr.id());
if (reference != null && !reference.overloadIds().isEmpty()) {
overloadIds = reference.overloadIds();
} else if (resolvedFunction.overloadId().isPresent()) {
overloadIds = ImmutableList.of(resolvedFunction.overloadId().get());
}

Expand Down Expand Up @@ -628,16 +637,23 @@ private static Builder newBuilder() {
}

static final class PlannerContext {
private final ImmutableMap<Long, CelReference> referenceMap;
private final ImmutableMap<Long, CelType> typeMap;
private final CelAbstractSyntaxTree ast;
private final HashMap<String, Integer> localVars = new HashMap<>();

CelAbstractSyntaxTree ast() {
return ast;
}

ImmutableMap<Long, CelReference> referenceMap() {
return referenceMap;
return ast.getReferenceMap();
}

ImmutableMap<Long, CelType> typeMap() {
return typeMap;
return ast.getTypeMap();
}

boolean isChecked() {
return ast.isChecked();
}

private void pushLocalVars(String... names) {
Expand Down Expand Up @@ -670,14 +686,12 @@ private boolean isLocalVar(String name) {
return localVars.containsKey(name);
}

private PlannerContext(
ImmutableMap<Long, CelReference> referenceMap, ImmutableMap<Long, CelType> typeMap) {
this.referenceMap = referenceMap;
this.typeMap = typeMap;
private PlannerContext(CelAbstractSyntaxTree ast) {
this.ast = checkNotNull(ast);
}

static PlannerContext create(CelAbstractSyntaxTree ast) {
return new PlannerContext(ast.getReferenceMap(), ast.getTypeMap());
return new PlannerContext(ast);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,30 @@ public enum SubtractOverload implements CelStandardOverload {
"subtract_timestamp_timestamp",
Instant.class,
Instant.class,
(Instant i1, Instant i2) -> java.time.Duration.between(i2, i1));
(Instant i1, Instant i2) -> {
java.time.Duration between = java.time.Duration.between(i2, i1);
try {
// Call toNanos() to validate 64-bit nanosecond overflow (throws
// ArithmeticException).
@SuppressWarnings("unused")
long unused = between.toNanos();
} catch (ArithmeticException e) {
throw new CelNumericOverflowException(e);
}
return between;
});
} else {
return CelFunctionBinding.from(
"subtract_timestamp_timestamp",
Timestamp.class,
Timestamp.class,
(Timestamp t1, Timestamp t2) -> ProtoTimeUtils.between(t2, t1));
(Timestamp t1, Timestamp t2) -> {
try {
return ProtoTimeUtils.between(t2, t1);
} catch (ArithmeticException e) {
throw new CelNumericOverflowException(e);
}
});
}
}),
SUBTRACT_TIMESTAMP_DURATION(
Expand Down
Loading