Skip to content

Fix issue #381: evalNautilusCall's argument loop needs static_val, not plain int#392

Merged
PhilippGrulich merged 3 commits into
mainfrom
claude/github-issue-381-lomwhq
Jul 11, 2026
Merged

Fix issue #381: evalNautilusCall's argument loop needs static_val, not plain int#392
PhilippGrulich merged 3 commits into
mainfrom
claude/github-issue-381-lomwhq

Conversation

@PhilippGrulich

@PhilippGrulich PhilippGrulich commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #381.

Root cause: Nautilus documents exactly two sanctioned trace-time loop constructs (docs/loops.md, docs/static-val.md): val<T> for real runtime loops, and static_val<T>/static_iterable for trace-time-unrolled loops — whose counter is folded into the tracer's Snapshot hash specifically so repeated call sites stay distinguishable (Tag identity is a raw __builtin_return_address chain, which depends only on call-stack shape, not on which logical operation it is).

The fuzzer's own evalNautilusCall (test/fuzz/EvalNautilus.hpp) evaluates a Kind::Call node's arguments with a plain int loop counter:

for (int i = 0; i < callDesc.arity; ++i) {
    v[i] = evalNautilusGeneric<T>(ast, n.kid[vStart + i], args, ctx);
}

This drives repeated evalNautilusGeneric()/invoke() calls through one shared, non-inlined call site — e.g. for same-shaped sibling Kind::Const leaves, or nested Kind::Call arguments targeting different callees — with no static_val disambiguation, unlike every other trace-time-unrolled loop already in this file (e.g. the StaticLoop handling). Two arguments reached through an identical call-stack shape collide onto the same Tag, which ExecutionTrace::processControlFlowMerge treats as an unconditional fatal "Invalid trace. This is maybe caused by a constant loop." error.

Fix: switch that loop's counter to static_val<int>.

Why not a tracer-side fix?

An earlier version of this PR patched the tracer instead (comparing callee identity on a Tag collision for Op::CALL/Op::FUNC_ADDR, mirroring the traceConstant/traceCopy (#95) and traceAssignment (#382) precedents). That approach doesn't generalize: there's no comparable "identity" to check for e.g. two colliding Op::ADD operations (their operands are always-different value refs regardless of whether it's a real revisit or a false collision), so the same collision would remain reachable for every other operation kind. The real, general-purpose fix belongs in the caller violating the documented loop-construct contract, not as a narrow tracer-side patch for one symptom — so this PR is now scoped entirely to test/fuzz/EvalNautilus.hpp plus the fuzz harness's tolerance list/docs.

Validation

Verified against the unmodified tracer (no tracer-side changes at all):

  • Before this fix: a standalone reproduction modeled on evalNautilusCall's exact loop shape reliably aborts with Invalid trace. This is maybe caused by a constant loop.
  • After this fix: the same reproduction succeeds.
  • Deterministic fuzz smoke corpus (nautilus-fuzz-replay, 2000 inputs): passes cleanly with zero tolerated findings.
  • --survey 8000: 0 findings.
  • Full ctest suite: 355/355 tests pass.
  • Changed files verified clean under clang-format-18 (.clang-format-compliant).

Test plan

  • ctest --test-dir nautilus — 355/355 passed
  • nautilus-fuzz-replay deterministic smoke corpus (2000 inputs) — clean, no tolerated findings
  • nautilus-fuzz-replay --survey 8000 — 0 findings
  • clang-format-18 --dry-run --Werror on all changed files

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracing Benchmark

Details
Benchmark suite Current: a8bf085 Previous: c09b79b Ratio
e2e_tiered_bc_to_mlir 3338.7400000000002 us (± 90261.3) 3408.15 us (± 112846) 0.98
e2e_single_mlir 5.56092 ms (± 139.088) 5.60554 ms (± 155.421) 0.99
tiered_twotier_addOne 3.35614 ms (± 114.551) 3.47247 ms (± 132.877) 0.97
tiered_singletier_addOne 3.37419 ms (± 317.153) 3.38833 ms (± 125.658) 1.00
single_compile_mlir_addOne 3.2327 ms (± 96.4737) 3.30667 ms (± 110.369) 0.98
exec_mlir_add 10.3442 ns (± 1.01167) 10.6819 ns (± 1.39873) 0.97
exec_mlir_fibonacci 13.5588 us (± 1.85573) 13.8233 us (± 1.84447) 0.98
exec_mlir_sum 538.982 us (± 25.6059) 587.18 us (± 32.3454) 0.92
exec_cpp_add 4.66649 ns (± 0.529892) 4.76776 ns (± 0.533983) 0.98
exec_cpp_fibonacci 48.6953 us (± 5.89739) 49.2349 us (± 6.73752) 0.99
exec_cpp_sum 11.3874 ms (± 81.3272) 11.6139 ms (± 1.13215) 0.98
exec_bc_add 46.0688 ns (± 4.96499) 46.5655 ns (± 4.71999) 0.99
exec_bc_fibonacci 433.458 us (± 13.56) 432.118 us (± 12.7696) 1.00
exec_bc_sum 95.3226 ms (± 1.4093) 95.6427 ms (± 771.627) 1.00
exec_tbc_add 27.4933 ns (± 3.70783) 26.987 ns (± 3.15199) 1.02
exec_tbc_fibonacci 148.031 us (± 11.1938) 142.321 us (± 6.88577) 1.04
exec_tbc_sum 36.5518 ms (± 163.983) 36.5133 ms (± 88.2632) 1.00
exec_asmjit_add 3.42913 ns (± 0.0776566) 3.48253 ns (± 0.366246) 0.98
exec_asmjit_fibonacci 14.3135 us (± 1.52745) 14.7163 us (± 2.84884) 0.97
exec_asmjit_sum 2.83618 ms (± 103.287) 2.81549 ms (± 67.9379) 1.01
exec_bc_add_passesOff 46.5834 ns (± 5.91548) 46.4387 ns (± 5.88624) 1.00
exec_bc_add_passesOn 45.996 ns (± 4.50691) 46.6337 ns (± 5.63974) 0.99
exec_bc_fibonacci_passesOff 431.647 us (± 12.897) 431.012 us (± 10.4921) 1.00
exec_bc_fibonacci_passesOn 383.277 us (± 18.7453) 390.069 us (± 16.2709) 0.98
exec_bc_sum_passesOff 94.717 ms (± 1.72965) 95.4333 ms (± 157.076) 0.99
exec_bc_sum_passesOn 79.1917 ms (± 1.34385) 79.6438 ms (± 95.5517) 0.99
exec_tbc_add_passesOff 26.6073 ns (± 2.24717) 26.6874 ns (± 2.63116) 1.00
exec_tbc_add_passesOn 26.7699 ns (± 2.70482) 27.5011 ns (± 3.63596) 0.97
exec_tbc_fibonacci_passesOff 157.335 us (± 28.603) 143.165 us (± 7.8211) 1.10
exec_tbc_fibonacci_passesOn 157.355 us (± 30.371) 142.997 us (± 6.94695) 1.10
exec_tbc_sum_passesOff 36.5854 ms (± 415.308) 36.5228 ms (± 63.1242) 1.00
exec_tbc_sum_passesOn 34.5275 ms (± 1.28882) 33.971 ms (± 176.734) 1.02
exec_asmjit_add_passesOff 3.52704 ns (± 0.496901) 3.49831 ns (± 0.388058) 1.01
exec_asmjit_add_passesOn 3.46478 ns (± 0.272292) 3.54397 ns (± 0.463242) 0.98
exec_asmjit_fibonacci_passesOff 14.4372 us (± 2.12463) 14.4214 us (± 1.66437) 1.00
exec_asmjit_fibonacci_passesOn 14.638 us (± 3.04248) 14.0952 us (± 815.043) 1.04
exec_asmjit_sum_passesOff 2.81264 ms (± 28.2527) 2.81455 ms (± 24.6192) 1.00
exec_asmjit_sum_passesOn 2.81143 ms (± 19.2269) 2.80224 ms (± 22.6856) 1.00
exec_bc_add_noRegAlloc 46.6043 ns (± 5.80838) 48.0475 ns (± 7.56764) 0.97
exec_bc_add_regAlloc 46.9471 ns (± 8.22876) 46.149 ns (± 4.04995) 1.02
exec_bc_fibonacci_noRegAlloc 432.695 us (± 12.9042) 432.396 us (± 11.8986) 1.00
exec_bc_fibonacci_regAlloc 430.079 us (± 10.0278) 432.449 us (± 13.3509) 0.99
exec_bc_sum_noRegAlloc 95.3304 ms (± 1.0842) 95.4629 ms (± 245.892) 1.00
exec_bc_sum_regAlloc 95.1778 ms (± 1.1435) 95.3771 ms (± 494.909) 1.00
exec_bc_add_call 45.3831 ns (± 3.73287) 46.567 ns (± 5.54434) 0.97
exec_bc_add_switch 41.1556 ns (± 3.42708) 41.3926 ns (± 4.23054) 0.99
exec_bc_add_threaded 40.9868 ns (± 7.83561) 39.8935 ns (± 6.44023) 1.03
exec_bc_fibonacci_call 433.864 us (± 16.0691) 431.113 us (± 11.0595) 1.01
exec_bc_fibonacci_switch 333.948 us (± 13.4028) 332.014 us (± 9.86769) 1.01
exec_bc_fibonacci_threaded 437.465 us (± 11.1542) 438.637 us (± 10.9572) 1.00
exec_bc_sum_call 95.5565 ms (± 1.86832) 95.3637 ms (± 150.297) 1.00
exec_bc_sum_switch 67.4098 ms (± 1.63394) 67.7239 ms (± 2.15734) 1.00
exec_bc_sum_threaded 86.7085 ms (± 680.525) 86.5178 ms (± 710.204) 1.00
exec_bc_add_threaded_noReuse 40.1302 ns (± 4.5798) 39.4759 ns (± 4.75548) 1.02
exec_bc_add_threaded_reuse 35.2521 ns (± 5.00974) 34.6864 ns (± 3.74675) 1.02
exec_bc_fibonacci_threaded_noReuse 437.886 us (± 12.4418) 438.957 us (± 12.4592) 1.00
exec_bc_fibonacci_threaded_reuse 437.028 us (± 11.4081) 438.838 us (± 11.2154) 1.00
exec_bc_sum_threaded_noReuse 86.6101 ms (± 470.488) 86.521 ms (± 470.783) 1.00
exec_bc_sum_threaded_reuse 86.7274 ms (± 202.754) 86.3725 ms (± 523.973) 1.00
exec_bc_add_threaded_noSuperinstr 40.5966 ns (± 6.30987) 40.0042 ns (± 7.7202) 1.01
exec_bc_add_threaded_superinstr 41.0406 ns (± 8.3966) 38.9563 ns (± 3.52786) 1.05
trace_add 2.39638 us (± 179.837) 2.47522 us (± 255.057) 0.97
completing_trace_add 2.40026 us (± 248.396) 2.35 us (± 206.492) 1.02
trace_ifThenElse 9.12993 us (± 1.55819) 9.03003 us (± 1.3322) 1.01
completing_trace_ifThenElse 4.75745 us (± 518.817) 4.78891 us (± 490.732) 0.99
trace_deeplyNestedIfElse 26.7898 us (± 2.80582) 26.8393 us (± 3.08202) 1.00
completing_trace_deeplyNestedIfElse 13.0981 us (± 1.48894) 13.3382 us (± 2.06966) 0.98
trace_loop 8.85132 us (± 979.381) 8.89502 us (± 1.0972) 1.00
completing_trace_loop 4.81793 us (± 489.169) 4.77518 us (± 477.832) 1.01
trace_ifInsideLoop 17.5965 us (± 2.39755) 17.8516 us (± 2.79598) 0.99
completing_trace_ifInsideLoop 8.80336 us (± 1.17584) 8.52896 us (± 1.04563) 1.03
trace_loopDirectCall 9.0397 us (± 1.04591) 9.13044 us (± 1.31266) 0.99
completing_trace_loopDirectCall 4.94575 us (± 516.27) 4.99249 us (± 534.124) 0.99
trace_pointerLoop 14.8368 us (± 2.84628) 14.6791 us (± 2.01417) 1.01
completing_trace_pointerLoop 10.5287 us (± 1.49575) 10.3823 us (± 1.4835) 1.01
trace_staticLoop 7.72552 us (± 850.575) 7.7207 us (± 782.16) 1.00
completing_trace_staticLoop 7.74722 us (± 757.997) 7.88802 us (± 884.666) 0.98
trace_fibonacci 10.3991 us (± 1.72637) 10.3939 us (± 1.57001) 1.00
completing_trace_fibonacci 6.38661 us (± 810.742) 6.30888 us (± 929.534) 1.01
trace_gcd 8.37908 us (± 1.60579) 8.20513 us (± 1.09603) 1.02
completing_trace_gcd 4.12717 us (± 1.10117) 4.0543 us (± 409.658) 1.02
trace_nestedIf10 44.4713 us (± 6.36464) 45.0942 us (± 6.58965) 0.99
completing_trace_nestedIf10 45.3119 us (± 6.50484) 46.5442 us (± 6.85501) 0.97
trace_nestedIf100 1.94869 ms (± 27.8748) 1.94637 ms (± 36.1216) 1.00
completing_trace_nestedIf100 1.99264 ms (± 33.2872) 2.00458 ms (± 32.3616) 0.99
trace_chainedIf10 105.043 us (± 7.33497) 105.221 us (± 8.40981) 1.00
completing_trace_chainedIf10 50.3509 us (± 6.36035) 51.9383 us (± 8.14667) 0.97
trace_chainedIf100 5.02866 ms (± 50.0585) 5.05983 ms (± 42.1173) 0.99
completing_trace_chainedIf100 2.36882 ms (± 35.3348) 2.39421 ms (± 41.2739) 0.99
comp_mlir_add 5.54098 ms (± 127.898) 5.65618 ms (± 231.962) 0.98
comp_mlir_ifThenElse 6.12795 ms (± 145.054) 6.43187 ms (± 227.296) 0.95
comp_mlir_deeplyNestedIfElse 5.01016 ms (± 121.906) 5.30126 ms (± 201.276) 0.95
comp_mlir_loop 7.10374 ms (± 157.795) 7.64637 ms (± 363.66) 0.93
comp_mlir_ifInsideLoop 29.0155 ms (± 1.22029) 30.1085 ms (± 874.866) 0.96
comp_mlir_loopDirectCall 11.8493 ms (± 319.579) 12.2741 ms (± 489.011) 0.97
comp_mlir_pointerLoop 27.9129 ms (± 573.711) 29.6437 ms (± 627.318) 0.94
comp_mlir_staticLoop 4.96914 ms (± 121.031) 5.02511 ms (± 140.803) 0.99
comp_mlir_fibonacci 10.42 ms (± 198.118) 11.3324 ms (± 571.23) 0.92
comp_mlir_gcd 9.38916 ms (± 187.642) 9.92803 ms (± 303.508) 0.95
comp_mlir_nestedIf10 10.4301 ms (± 151.535) 10.7095 ms (± 204.879) 0.97
comp_mlir_nestedIf100 24.8186 ms (± 298.127) 25.586 ms (± 489.591) 0.97
comp_mlir_chainedIf10 9.59291 ms (± 221.621) 9.62625 ms (± 199.061) 1.00
comp_mlir_chainedIf100 20.3241 ms (± 361.16) 20.8666 ms (± 439.135) 0.97
comp_cpp_add 24.9278 ms (± 324.19) 25.7219 ms (± 654.372) 0.97
comp_cpp_ifThenElse 25.242 ms (± 347.881) 26.313 ms (± 1.09227) 0.96
comp_cpp_deeplyNestedIfElse 26.7804 ms (± 404.931) 26.4038 ms (± 585.057) 1.01
comp_cpp_loop 25.3647 ms (± 404.892) 25.9866 ms (± 572.753) 0.98
comp_cpp_ifInsideLoop 25.542 ms (± 415.285) 26.6014 ms (± 1.50125) 0.96
comp_cpp_loopDirectCall 25.6926 ms (± 508.654) 26.7357 ms (± 920.062) 0.96
comp_cpp_pointerLoop 25.7602 ms (± 1.25263) 26.6561 ms (± 692.924) 0.97
comp_cpp_staticLoop 25.3178 ms (± 499.903) 26.415 ms (± 662.785) 0.96
comp_cpp_fibonacci 25.2664 ms (± 397.551) 25.7256 ms (± 468.79) 0.98
comp_cpp_gcd 25.6135 ms (± 1.84076) 25.8934 ms (± 398.765) 0.99
comp_cpp_nestedIf10 27.7677 ms (± 644.656) 29.1888 ms (± 703.11) 0.95
comp_cpp_nestedIf100 52.6713 ms (± 358.492) 53.5487 ms (± 864.76) 0.98
comp_cpp_chainedIf10 28.0984 ms (± 465.304) 28.697 ms (± 656.171) 0.98
comp_cpp_chainedIf100 56.9419 ms (± 728.692) 58.5236 ms (± 1.30983) 0.97
comp_bc_add 15.043 us (± 2.26778) 15.2253 us (± 2.3477) 0.99
comp_bc_ifThenElse 20.3696 us (± 5.0366) 20.2331 us (± 3.42153) 1.01
comp_bc_deeplyNestedIfElse 25.1705 us (± 4.52462) 25.4193 us (± 4.51699) 0.99
comp_bc_loop 20.0497 us (± 3.39577) 20.4043 us (± 3.46753) 0.98
comp_bc_ifInsideLoop 23.9772 us (± 3.69179) 25.2308 us (± 5.01192) 0.95
comp_bc_loopDirectCall 20.9804 us (± 3.83) 21.494 us (± 3.76104) 0.98
comp_bc_pointerLoop 22.3826 us (± 4.34691) 23.0236 us (± 4.0031) 0.97
comp_bc_staticLoop 18.113 us (± 3.57814) 18.8934 us (± 3.87904) 0.96
comp_bc_fibonacci 20.3762 us (± 2.73671) 21.2409 us (± 4.29992) 0.96
comp_bc_gcd 19.8115 us (± 3.6074) 20.1625 us (± 4.23202) 0.98
comp_bc_nestedIf10 47.0858 us (± 6.52165) 49.4465 us (± 7.8924) 0.95
comp_bc_nestedIf100 279.372 us (± 11.362) 272.508 us (± 10.2274) 1.03
comp_bc_chainedIf10 62.7447 us (± 9.1596) 64.3958 us (± 8.8905) 0.97
comp_bc_chainedIf100 451.29 us (± 15.6301) 444.472 us (± 16.6502) 1.02
comp_tbc_add 1.81562 us (± 130.447) 1.90203 us (± 165.432) 0.95
comp_tbc_ifThenElse 4.07986 us (± 511.012) 4.11024 us (± 364.396) 0.99
comp_tbc_deeplyNestedIfElse 9.49686 us (± 1.39944) 9.41954 us (± 1.00386) 1.01
comp_tbc_loop 4.10751 us (± 301.397) 4.20539 us (± 284.784) 0.98
comp_tbc_ifInsideLoop 7.10568 us (± 730.459) 7.35922 us (± 940.403) 0.97
comp_tbc_loopDirectCall 4.48494 us (± 407.579) 4.42563 us (± 393.502) 1.01
comp_tbc_pointerLoop 5.37438 us (± 381.227) 5.5009 us (± 466.27) 0.98
comp_tbc_staticLoop 4.49352 us (± 426.346) 4.51782 us (± 376.877) 0.99
comp_tbc_fibonacci 4.60571 us (± 533.773) 4.62891 us (± 580.639) 0.99
comp_tbc_gcd 3.71857 us (± 353.596) 3.79779 us (± 364.596) 0.98
comp_tbc_nestedIf10 25.835 us (± 2.58741) 26.237 us (± 3.02759) 0.98
comp_tbc_nestedIf100 278.907 us (± 15.4102) 269.481 us (± 9.3425) 1.03
comp_tbc_chainedIf10 33.6882 us (± 3.48324) 33.7404 us (± 3.35796) 1.00
comp_tbc_chainedIf100 397.746 us (± 15.1169) 398.393 us (± 16.0394) 1.00
comp_asmjit_add 23.1745 us (± 4.33704) 24.8203 us (± 5.29972) 0.93
comp_asmjit_ifThenElse 32.3719 us (± 5.3189) 33.3687 us (± 5.52414) 0.97
comp_asmjit_deeplyNestedIfElse 48.2151 us (± 7.73263) 51.5486 us (± 13.6798) 0.94
comp_asmjit_loop 32.4364 us (± 4.96801) 33.92 us (± 5.30811) 0.96
comp_asmjit_ifInsideLoop 46.8316 us (± 8.36799) 47.2439 us (± 9.17291) 0.99
comp_asmjit_loopDirectCall 35.913 us (± 4.12925) 37.3175 us (± 6.11285) 0.96
comp_asmjit_pointerLoop 37.3617 us (± 5.00694) 38.2988 us (± 5.35749) 0.98
comp_asmjit_staticLoop 29.0085 us (± 4.92416) 30.316 us (± 4.88707) 0.96
comp_asmjit_fibonacci 34.0194 us (± 5.02802) 35.6718 us (± 7.00096) 0.95
comp_asmjit_gcd 33.1622 us (± 4.82279) 33.597 us (± 4.71356) 0.99
comp_asmjit_nestedIf10 76.5713 us (± 10.5353) 79.4687 us (± 12.2171) 0.96
comp_asmjit_nestedIf100 492.002 us (± 12.4232) 496.841 us (± 21.1121) 0.99
comp_asmjit_chainedIf10 94.5571 us (± 10.9265) 95.0332 us (± 11.2951) 0.99
comp_asmjit_chainedIf100 641.916 us (± 29.8436) 636.014 us (± 19.7759) 1.01
exec_bc_addOne 41.1162 ns (± 6.57232) 40.6811 ns (± 5.80606) 1.01
exec_mlir_addOne 291.723 ns (± 7.41424) 276.958 ns (± 6.43566) 1.05
exec_cpp_addOne 3.95305 ns (± 0.525009) 4.03401 ns (± 0.739845) 0.98
exec_interpreted_addOne 38.3819 ns (± 2.03564) 38.3377 ns (± 1.83669) 1.00
ssa_add 179.677 ns (± 11.8684) 187.561 ns (± 18.6427) 0.96
ssa_ifThenElse 442.864 ns (± 45.0261) 453.324 ns (± 40.7916) 0.98
ssa_deeplyNestedIfElse 1.1269 us (± 79.4867) 1.11579 us (± 119.211) 1.01
ssa_loop 475.759 ns (± 32.5807) 501.91 ns (± 111.095) 0.95
ssa_ifInsideLoop 876.307 ns (± 54.1532) 859.989 ns (± 61.2846) 1.02
ssa_loopDirectCall 485.571 ns (± 33.8976) 498.968 ns (± 46.5808) 0.97
ssa_pointerLoop 575.357 ns (± 43.7227) 598.014 ns (± 55.6541) 0.96
ssa_staticLoop 396.828 ns (± 19.027) 411.502 ns (± 31.5452) 0.96
ssa_fibonacci 492.498 ns (± 32.376) 501.86 ns (± 42.7938) 0.98
ssa_gcd 443.396 ns (± 33.6368) 453.204 ns (± 52.8308) 0.98
ir_add 763.451 ns (± 68.1602) 794.934 ns (± 46.3606) 0.96
ir_ifThenElse 1.58019 us (± 103.83) 1.63348 us (± 114.165) 0.97
ir_deeplyNestedIfElse 3.38966 us (± 400.752) 3.48113 us (± 414.87) 0.97
ir_loop 1.65836 us (± 98.5202) 1.71589 us (± 153.529) 0.97
ir_ifInsideLoop 2.82066 us (± 195.285) 2.9738 us (± 309.573) 0.95
ir_loopDirectCall 1.81306 us (± 128.114) 1.92769 us (± 254.512) 0.94
ir_pointerLoop 1.99892 us (± 162.823) 2.1313 us (± 277.775) 0.94
ir_staticLoop 1.42308 us (± 96.5925) 1.45134 us (± 120.715) 0.98
ir_fibonacci 1.82891 us (± 154.071) 1.85883 us (± 185.944) 0.98
ir_gcd 1.50576 us (± 102.46) 1.53676 us (± 116.928) 0.98
ir_nestedIf10 7.58023 us (± 628.27) 7.72152 us (± 606.434) 0.98
ir_nestedIf100 88.2918 us (± 5.24927) 87.2424 us (± 6.36617) 1.01
ir_chainedIf10 11.4629 us (± 751.886) 11.6452 us (± 828.889) 0.98
ir_chainedIf100 167.765 us (± 9.63691) 165.242 us (± 9.56224) 1.02

This comment was automatically generated by workflow using github-action-benchmark.

@PhilippGrulich PhilippGrulich changed the title Fix Tag/Snapshot collision for Op::CALL/FUNC_ADDR through a shared dispatch site Fix issue #381: evalNautilusCall's argument loop needs static_val, not plain int Jul 10, 2026
@PhilippGrulich
PhilippGrulich marked this pull request as ready for review July 11, 2026 06:26
claude added 3 commits July 11, 2026 08:26
…spatch site (#381)

Tag identity is a raw __builtin_return_address chain (TagRecorder.cpp), which
depends only on the call-stack shape used to reach a traced operation, not on
which logical operation it is. A tracing client that dispatches every call
through one shared, non-inlined call site (e.g. a recursive expression
evaluator resolving its callee at runtime, exactly how a query compiler uses
Nautilus) can therefore produce byte-identical Tags for two unrelated
Op::CALL/Op::FUNC_ADDR operations targeting different callees.
ExecutionTrace::processControlFlowMerge treated any such same-block Tag match
as an unconditional fatal "Invalid trace. This is maybe caused by a constant
loop." error.

Add LazyTraceContext::traceCallOperation / ExceptionBasedTraceContext::traceCallOperation,
which compare the callee (FunctionCall::ptr) already recorded at a colliding
tag against the one about to be traced. A mismatch means the collision is
coincidental, not a genuine control-flow re-entry, so the call is recorded
fresh instead of forcing a bogus merge -- the same reconciliation strategy
already used for traceConstant/traceCopy (issue #95) and traceAssignment
(issue #382) for this identical underlying Tag-collision defect.

Pin the fix with a deterministic regression test (sharedCallSiteDifferentCallees)
that reproduces the collision independent of the fuzzer's own byte-stream, and
update the fuzz README/ReplayMain.cpp tolerance list now that this finding no
longer needs to be tolerated by the smoke corpus.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YEWvnFt8PCUecby1YBywP
…tic_val

Verified empirically that a static_val/static_iterable-driven trace-time
kernel loop already sidesteps this specific collision (static_val's counter
feeds Snapshot::staticValueHash), and that a plain, un-annotated host loop is
required to reproduce it -- confirmed against a true pre-fix build in a
throwaway worktree.

But the actual defect (per issue #381 and the differential fuzzer's confirmed
findings) lives one layer further out: in generic interpreter/compiler
infrastructure driving Nautilus's tracing API from outside any single kernel
body (e.g. evalNautilusCall's own argument-evaluation loop in
test/fuzz/EvalNautilus.hpp), which has no static_val to reach for. Confirmed
by modeling that exact loop shape (nested Kind::Call arguments evaluated
through one shared, plain-int loop) and reproducing the same collision
against a true pre-fix build.

Document this distinction in the regression test so a future reader doesn't
mistake it for a kernel-authoring bug fixable by "just use static_val".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YEWvnFt8PCUecby1YBywP
Nautilus documents exactly two sanctioned trace-time loop constructs
(docs/loops.md, docs/static-val.md): val<T> for real runtime loops, and
static_val<T>/static_iterable for trace-time-unrolled loops, whose counter is
folded into the tracer's Snapshot hash specifically to keep repeated call
sites distinguishable. A plain host `int`/`for` counter driving repeated
trace calls is not a supported pattern.

The root cause of issue #381 was exactly that: evalNautilusCall's own
argument-evaluation loop (test/fuzz/EvalNautilus.hpp) used a plain `int`
counter to evaluate a Kind::Call node's arguments, driving repeated
evalNautilusGeneric()/invoke() calls through one shared call site with no
static_val disambiguation -- unlike every other trace-time-unrolled loop
already in this file (e.g. StaticLoop). Fixed by switching that loop's
counter to static_val<int>.

Revert the previous LazyTraceContext.cpp/ExceptionBasedTraceContext.cpp
tracer-level fix and its regression test: it only patched Op::CALL/FUNC_ADDR
by comparing callee identity, which doesn't generalize (there is no
comparable "identity" to check for e.g. two colliding Op::ADD operations, so
the same collision remains possible for every other operation kind), and the
real, general-purpose fix belongs in the caller that violates the documented
loop-construct contract, not as a narrow tracer-side patch for one symptom.

Verified against the true pre-fix tracer (unmodified, no local changes): with
only the EvalNautilus.hpp fix applied, the deterministic smoke corpus (2000
inputs) and a --survey of 8000 inputs both pass with zero collisions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YEWvnFt8PCUecby1YBywP
@PhilippGrulich
PhilippGrulich force-pushed the claude/github-issue-381-lomwhq branch from 898fea7 to a8bf085 Compare July 11, 2026 06:26
@PhilippGrulich
PhilippGrulich merged commit 57e8585 into main Jul 11, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants