Skip to content

Commit 46e11e8

Browse files
Add --max-stack / -s flag to limit stack depth (#637)
## Summary - Adds a `--max-stack` / `-s` CLI flag (default 500) to limit the evaluation stack depth, matching go-jsonnet's `-s` / `--max-stack` option. - Introduces a stack frame counter in the Evaluator, incremented/decremented at function calls (`Apply*`, `ApplyBuiltin*`), object field evaluation (`invoke`), imports, and default parameter evaluation. - When the counter exceeds `maxStack`, a clear `sjsonnet.Error: Max stack frames exceeded.` is thrown instead of a raw JVM `StackOverflowError`. ## Test plan - [x] JVM tests pass (140/140) - [x] WASM tests pass (333/333) - [x] New unit tests for recursive functions, mutual recursion, depth within limits, and builtin calls - [x] Golden files updated for `error.recursive_function_nonterm`, `error.recursive_import`, `error.recursive_object_non_term`, and `error.function_infinite_default` - [x] CLI flag verified with `--max-stack` and `-s` short form
1 parent ad4edb1 commit 46e11e8

12 files changed

Lines changed: 241 additions & 4225 deletions

build.mill

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ trait SjsonnetCrossModule extends CrossScalaModule with ScalafmtModule {
7878
"-feature",
7979
"-opt-inline-from:sjsonnet.*,sjsonnet.**",
8080
"-Xsource:3",
81-
"-Xlint:_"
82-
) ++ (if (scalaVersion().startsWith("2.13")) Seq("-Wconf:origin=scala.collection.compat.*:s")
81+
"-Xlint:_",
82+
) ++ (if (scalaVersion().startsWith("2.13")) Seq("-Wopt", "-Wconf:origin=scala.collection.compat.*:s")
8383
else Seq("-Xfatal-warnings", "-Ywarn-unused:-nowarn"))
8484
else Seq[String]("-Wconf:origin=scala.collection.compat.*:s", "-Xlint:all")
8585
)

sjsonnet/src-jvm-native/sjsonnet/Config.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ final case class Config(
161161
doc = "Print runtime statistics (thunks, calls, imports, timing) to stderr after evaluation"
162162
)
163163
debugStats: Flag = Flag(),
164+
@arg(
165+
name = "max-stack",
166+
short = 's',
167+
doc = "Number of allowed stack frames (default 500)"
168+
)
169+
maxStack: Int = 500,
164170
@arg(
165171
doc = "The jsonnet file you wish to evaluate",
166172
positional = true

sjsonnet/src-jvm-native/sjsonnet/SjsonnetMainBase.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ object SjsonnetMainBase {
155155
strict = config.strict.value,
156156
throwErrorForInvalidSets = config.throwErrorForInvalidSets.value,
157157
maxParserRecursionDepth = config.maxParserRecursionDepth,
158-
brokenAssertionLogic = config.brokenAssertionLogic.value
158+
brokenAssertionLogic = config.brokenAssertionLogic.value,
159+
maxStack = config.maxStack
159160
),
160161
parseCache,
161162
wd,

0 commit comments

Comments
 (0)