3232
3333#include " absl/algorithm/container.h"
3434#include " absl/base/nullability.h"
35+ #include " absl/cleanup/cleanup.h"
3536#include " absl/container/flat_hash_map.h"
3637#include " absl/container/flat_hash_set.h"
3738#include " absl/container/node_hash_map.h"
@@ -971,13 +972,13 @@ class FlatExprVisitor : public cel::AstVisitor {
971972 *std::move (field_type), select_expr.test_only (),
972973 options_.enable_empty_wrapper_null_unboxing ,
973974 enable_optional_types_),
974- expr.id ());
975+ expr.id (), /* stack_delta= */ 0 );
975976 return ;
976977 }
977978 AddStep (CreateSelectStep (std::move (field), select_expr.test_only (),
978979 options_.enable_empty_wrapper_null_unboxing ,
979980 enable_optional_types_),
980- expr.id ());
981+ expr.id (), /* stack_delta= */ 0 );
981982 }
982983
983984 // Call node handler group.
@@ -1383,9 +1384,14 @@ class FlatExprVisitor : public cel::AstVisitor {
13831384 std::vector<std::string> fields =
13841385 std::move (status_or_resolved_fields.value ().second );
13851386
1387+ size_t num_fields = fields.size ();
1388+ int64_t stack_delta =
1389+ num_fields <= static_cast <size_t >(std::numeric_limits<int64_t >::max ())
1390+ ? 1 - static_cast <int64_t >(num_fields)
1391+ : std::numeric_limits<int16_t >::max ();
13861392 AddStep (CreateCreateStructStep (std::move (resolved_name), std::move (fields),
13871393 MakeOptionalIndicesSet (struct_expr)),
1388- expr.id ());
1394+ expr.id (), stack_delta );
13891395 }
13901396
13911397 void PostVisitMap (const cel::Expr& expr,
@@ -1406,9 +1412,15 @@ class FlatExprVisitor : public cel::AstVisitor {
14061412 }
14071413 }
14081414
1409- AddStep (CreateCreateStructStepForMap (map_expr.entries ().size (),
1415+ size_t num_entries = map_expr.entries ().size ();
1416+ int64_t stack_delta =
1417+ num_entries <=
1418+ static_cast <size_t >(std::numeric_limits<int64_t >::max () / 2 )
1419+ ? 1 - 2 * static_cast <int64_t >(num_entries)
1420+ : std::numeric_limits<int16_t >::max ();
1421+ AddStep (CreateCreateStructStepForMap (num_entries,
14101422 MakeOptionalIndicesSet (map_expr)),
1411- expr.id ());
1423+ expr.id (), stack_delta );
14121424 }
14131425
14141426 absl::Status progress_status () const { return progress_status_; }
@@ -1471,21 +1483,22 @@ class FlatExprVisitor : public cel::AstVisitor {
14711483 // may free the step at that point.
14721484 template <typename T>
14731485 std::enable_if_t <std::is_base_of_v<ExpressionStepLogic, T>, T*> AddStep (
1474- std::unique_ptr<T> step, int64_t expr_id = -1 ) {
1486+ std::unique_ptr<T> step, int64_t expr_id = -1 , int64_t stack_delta = 1 ) {
14751487 if (progress_status_.ok () && !PlanningSuppressed ()) {
14761488 T* ptr = step.get ();
1477- program_builder_.AddStep (
1478- ExpressionStep::MakeGenericStep ( std::move (step), expr_id));
1489+ program_builder_.AddStep (ExpressionStep::MakeGenericStep (
1490+ std::move (step), expr_id, stack_delta ));
14791491 return ptr;
14801492 }
14811493 return nullptr ;
14821494 }
14831495
14841496 template <typename T>
14851497 std::enable_if_t <std::is_base_of_v<ExpressionStepLogic, T>, T*> AddStep (
1486- absl::StatusOr<std::unique_ptr<T>> step, int64_t expr_id = -1 ) {
1498+ absl::StatusOr<std::unique_ptr<T>> step, int64_t expr_id = -1 ,
1499+ int64_t stack_delta = 1 ) {
14871500 if (step.ok ()) {
1488- return AddStep (*std::move (step), expr_id);
1501+ return AddStep (*std::move (step), expr_id, stack_delta );
14891502 } else {
14901503 SetProgressStatusIfError (step.status ());
14911504 }
@@ -1728,7 +1741,7 @@ FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleIndex(
17281741 }
17291742
17301743 AddStep (CreateContainerAccessStep (call_expr, enable_optional_types_),
1731- expr.id ());
1744+ expr.id (), /* stack_delta= */ - 1 );
17321745 return CallHandlerResult::kIntercepted ;
17331746}
17341747
@@ -2041,7 +2054,7 @@ void ExhaustiveTernaryCondVisitor::PreVisit(const cel::Expr* expr) {
20412054}
20422055
20432056void ExhaustiveTernaryCondVisitor::PostVisit (const cel::Expr* expr) {
2044- visitor_->AddStep (CreateTernaryStep (), expr->id ());
2057+ visitor_->AddStep (CreateTernaryStep (), expr->id (), /* stack_delta= */ - 2 );
20452058}
20462059
20472060void ComprehensionVisitor::PreVisit (const cel::Expr* expr) {
@@ -2232,6 +2245,52 @@ std::vector<ExecutionPathView> FlattenExpressionTable(
22322245 return subexpression_indexes;
22332246}
22342247
2248+ std::optional<int64_t > CheckedDeltaAdd (int64_t current,
2249+ std::optional<int64_t > delta) {
2250+ if (!delta.has_value ()) {
2251+ return std::nullopt ;
2252+ }
2253+ if (*delta > 0 && current > std::numeric_limits<int64_t >::max () - *delta) {
2254+ return std::nullopt ;
2255+ }
2256+ if (*delta < 0 && current < std::numeric_limits<int64_t >::min () - *delta) {
2257+ return std::nullopt ;
2258+ }
2259+ current += *delta;
2260+ if (current < 0 ) {
2261+ return std::nullopt ;
2262+ }
2263+ return current;
2264+ }
2265+
2266+ // Conservative estimate of the maximum value stack size needed for the given
2267+ // subexpressions.
2268+ //
2269+ // If overflow occurs, returns fallback_size, which is the total number of
2270+ // steps in the program.
2271+ size_t EstimateMaxStackSize (absl::Span<const ExecutionPathView> subexpressions,
2272+ size_t fallback_size) {
2273+ size_t total_max_stack = 0 ;
2274+ for (ExecutionPathView path : subexpressions) {
2275+ int64_t current = 0 ;
2276+ int64_t max_depth = 0 ;
2277+ for (const ExpressionStep& step : path) {
2278+ std::optional<int64_t > next = CheckedDeltaAdd (current, step.StackDelta ());
2279+ if (!next.has_value ()) {
2280+ return fallback_size;
2281+ }
2282+ current = *next;
2283+ max_depth = std::max (max_depth, current);
2284+ }
2285+ if (static_cast <uint64_t >(max_depth) >
2286+ std::numeric_limits<size_t >::max () - total_max_stack) {
2287+ return fallback_size;
2288+ }
2289+ total_max_stack += static_cast <size_t >(max_depth);
2290+ }
2291+ return total_max_stack;
2292+ }
2293+
22352294absl::Status CheckAstExtensions (
22362295 const std::vector<cel::ExtensionSpec>& extensions,
22372296 bool enable_select_optimization) {
@@ -2266,11 +2325,27 @@ absl::StatusOr<FlatExpression> FlatExprBuilder::CreateExpressionImpl(
22662325 ? RuntimeIssue::Severity::kWarning
22672326 : RuntimeIssue::Severity::kError ;
22682327 IssueCollector issue_collector (max_severity);
2328+ auto record_issues = absl::MakeCleanup ([issues, &issue_collector] {
2329+ if (issues == nullptr ) {
2330+ return ;
2331+ }
2332+ *issues = issue_collector.ExtractIssues ();
2333+ });
22692334
2270- CEL_ASSIGN_OR_RETURN (std::vector<cel::ExtensionSpec> runtime_extensions,
2271- ExtractAndValidateRuntimeExtensions (*ast));
2272- CEL_RETURN_IF_ERROR (
2273- CheckAstExtensions (runtime_extensions, enable_select_optimization_));
2335+ absl::StatusOr<std::vector<cel::ExtensionSpec>> runtime_extensions =
2336+ ExtractAndValidateRuntimeExtensions (*ast);
2337+
2338+ if (!runtime_extensions.ok ()) {
2339+ CEL_RETURN_IF_ERROR (issue_collector.AddIssue (
2340+ RuntimeIssue::CreateError (runtime_extensions.status ())));
2341+ } else {
2342+ absl::Status status =
2343+ CheckAstExtensions (*runtime_extensions, enable_select_optimization_);
2344+ if (!status.ok ()) {
2345+ CEL_RETURN_IF_ERROR (
2346+ issue_collector.AddIssue (RuntimeIssue::CreateError (status)));
2347+ }
2348+ }
22742349
22752350 Resolver resolver (container_, function_registry_, type_registry_,
22762351 GetTypeProvider (),
@@ -2318,17 +2393,16 @@ absl::StatusOr<FlatExpression> FlatExprBuilder::CreateExpressionImpl(
23182393 " Expression too large to be executed, exceeds uint32_t limits." );
23192394 }
23202395
2321- if (issues != nullptr ) {
2322- (*issues) = issue_collector.ExtractIssues ();
2323- }
2324-
23252396 ExecutionPath execution_path;
23262397 std::vector<ExecutionPathView> subexpressions =
23272398 FlattenExpressionTable (program_builder, execution_path);
2399+ size_t value_stack_size =
2400+ EstimateMaxStackSize (subexpressions, execution_path.size ());
23282401
23292402 return FlatExpression (std::move (execution_path), std::move (subexpressions),
23302403 visitor.slot_count (), visitor.iter_stack_count (),
2331- GetTypeProvider (), options_, std::move (arena));
2404+ GetTypeProvider (), options_, std::move (arena),
2405+ value_stack_size);
23322406}
23332407const cel::TypeProvider& FlatExprBuilder::GetTypeProvider () const {
23342408 return use_legacy_type_provider_
0 commit comments