From 7a66fef89ea097fc921253604009bca411d0f12d Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Wed, 15 Oct 2025 08:41:48 -0700 Subject: [PATCH] Fix crash in coverage collection of bool nodes which return an error. PiperOrigin-RevId: 819772476 --- testing/testrunner/BUILD | 30 ++++++++ testing/testrunner/coverage_index.cc | 2 +- testing/testrunner/coverage_index_test.cc | 93 +++++++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 testing/testrunner/coverage_index_test.cc diff --git a/testing/testrunner/BUILD b/testing/testrunner/BUILD index 10b906028..949dc56e7 100644 --- a/testing/testrunner/BUILD +++ b/testing/testrunner/BUILD @@ -177,3 +177,33 @@ cc_library( "@com_google_cel_spec//proto/cel/expr:syntax_cc_proto", ], ) + +cc_test( + name = "coverage_index_test", + srcs = ["coverage_index_test.cc"], + deps = [ + ":coverage_index", + "//checker:type_checker_builder", + "//checker:validation_result", + "//common:ast", + "//common:ast_proto", + "//common:decl", + "//common:type", + "//common:value", + "//compiler", + "//compiler:compiler_factory", + "//compiler:standard_library", + "//internal:status_macros", + "//internal:testing", + "//internal:testing_descriptor_pool", + "//runtime", + "//runtime:activation", + "//runtime:runtime_builder", + "//runtime:standard_runtime_builder_factory", + "@com_google_absl//absl/status:status_matchers", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings:string_view", + "@com_google_cel_spec//proto/cel/expr:syntax_cc_proto", + "@com_google_protobuf//:protobuf", + ], +) diff --git a/testing/testrunner/coverage_index.cc b/testing/testrunner/coverage_index.cc index 3fb5a9c3b..2746e3528 100644 --- a/testing/testrunner/coverage_index.cc +++ b/testing/testrunner/coverage_index.cc @@ -175,7 +175,7 @@ void TraverseAndCalculateCoverage( void CoverageIndex::RecordCoverage(int64_t node_id, const cel::Value& value) { NodeCoverageStats& stats = node_coverage_stats_[node_id]; stats.covered = true; - if (node_coverage_stats_[node_id].is_boolean_node) { + if (node_coverage_stats_[node_id].is_boolean_node && value.IsBool()) { if (value.AsBool()->NativeValue()) { stats.has_true_branch = true; } else { diff --git a/testing/testrunner/coverage_index_test.cc b/testing/testrunner/coverage_index_test.cc new file mode 100644 index 000000000..32417b2e9 --- /dev/null +++ b/testing/testrunner/coverage_index_test.cc @@ -0,0 +1,93 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "testing/testrunner/coverage_index.h" + +#include +#include + +#include "cel/expr/syntax.pb.h" +#include "absl/status/status_matchers.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "checker/type_checker_builder.h" +#include "checker/validation_result.h" +#include "common/ast.h" +#include "common/ast_proto.h" +#include "common/decl.h" +#include "common/type.h" +#include "common/value.h" +#include "compiler/compiler.h" +#include "compiler/compiler_factory.h" +#include "compiler/standard_library.h" +#include "internal/status_macros.h" +#include "internal/testing.h" +#include "internal/testing_descriptor_pool.h" +#include "runtime/activation.h" +#include "runtime/runtime.h" +#include "runtime/runtime_builder.h" +#include "runtime/standard_runtime_builder_factory.h" +#include "google/protobuf/arena.h" + +namespace cel::test { +namespace { + +using ::absl_testing::IsOk; +using ::cel::expr::CheckedExpr; + +absl::StatusOr> CreateTestRuntime() { + CEL_ASSIGN_OR_RETURN(cel::RuntimeBuilder standard_runtime_builder, + cel::CreateStandardRuntimeBuilder( + cel::internal::GetTestingDescriptorPool(), {})); + return std::move(standard_runtime_builder).Build(); +} + +TEST(CoverageIndexTest, RecordCoverageWithErrorDoesNotCrash) { + ASSERT_OK_AND_ASSIGN( + std::unique_ptr compiler_builder, + cel::NewCompilerBuilder(cel::internal::GetTestingDescriptorPool())); + ASSERT_THAT(compiler_builder->AddLibrary(cel::StandardCompilerLibrary()), + IsOk()); + ASSERT_THAT(compiler_builder->GetCheckerBuilder().AddVariable( + cel::MakeVariableDecl("x", cel::IntType())), + IsOk()); + ASSERT_OK_AND_ASSIGN(std::unique_ptr compiler, + std::move(compiler_builder)->Build()); + ASSERT_OK_AND_ASSIGN(cel::ValidationResult validation_result, + compiler->Compile("1/x > 1")); + CheckedExpr checked_expr; + ASSERT_THAT(cel::AstToCheckedExpr(*validation_result.GetAst(), &checked_expr), + IsOk()); + + CoverageIndex coverage_index; + coverage_index.Init(checked_expr); + + ASSERT_OK_AND_ASSIGN(std::unique_ptr runtime, + CreateTestRuntime()); + ASSERT_THAT(EnableCoverageInRuntime(*const_cast(runtime.get()), + coverage_index), + IsOk()); + ASSERT_OK_AND_ASSIGN(std::unique_ptr ast, + cel::CreateAstFromCheckedExpr(checked_expr)); + ASSERT_OK_AND_ASSIGN(auto program, runtime->CreateProgram(std::move(ast))); + + cel::Activation activation; + activation.InsertOrAssignValue("x", cel::IntValue(0)); + google::protobuf::Arena arena; + ASSERT_OK_AND_ASSIGN(cel::Value result, + program->Evaluate(&arena, activation)); + EXPECT_TRUE(result.IsError()); +} + +} // namespace +} // namespace cel::test