Skip to content

Commit ae5d019

Browse files
committed
fix: use the correct calling convention when over-applying a closure in lean_apply_m
This PR fixes a crash when more than 16 arguments are applied at once to a closure whose arity is at most 16. Deeply nested monad stacks can produce such applications, and the result was memory corruption rather than a clean call. `lean_apply_m` handles applications of more than 16 arguments. Its over-application branch invoked the closure through `FNN`, which passes arguments as an array. That convention is only correct for closures whose arity exceeds `LEAN_CLOSURE_MAX_ARGS`; below that the generated code takes its arguments separately, so the callee received the argument array in its first parameter and register garbage in the rest. The fixed-arity `lean_apply_N` functions already guard this, `lean_apply_15` even asserting `arity > 16` immediately before its `FNN` call. The over-application branch now applies the first `arity - fixed` arguments via `lean_apply_n`, which dispatches on the count and consumes the closure, and continues with the remainder.
1 parent 696e847 commit ae5d019

1 file changed

Lines changed: 15 additions & 6 deletions

File tree

src/runtime/apply.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -890,12 +890,21 @@ if (arity == fixed + n) {
890890
lean_dec_ref(f);
891891
return r;
892892
} else if (arity < fixed + n) {
893-
obj ** args = static_cast<obj**>(LEAN_ALLOCA(arity*sizeof(obj*))); // NOLINT
894-
for (unsigned i = 0; i < fixed; i++) { lean_inc(fx(i)); args[i] = fx(i); }
895-
for (unsigned i = 0; i < arity-fixed; i++) args[fixed+i] = as[i];
896-
obj * new_f = FNN(f)(args);
897-
lean_dec_ref(f);
898-
return lean_apply_n(new_f, n+fixed-arity, &as[arity-fixed]);
893+
unsigned m = arity - fixed;
894+
obj * new_f;
895+
if (arity > LEAN_CLOSURE_MAX_ARGS) {
896+
// `f`'s code takes its arguments as an array
897+
obj ** args = static_cast<obj**>(LEAN_ALLOCA(arity*sizeof(obj*))); // NOLINT
898+
for (unsigned i = 0; i < fixed; i++) { lean_inc(fx(i)); args[i] = fx(i); }
899+
for (unsigned i = 0; i < m; i++) args[fixed+i] = as[i];
900+
new_f = FNN(f)(args);
901+
lean_dec_ref(f);
902+
} else {
903+
// `f`'s code takes `arity` separate arguments, so it must not be invoked through `FNN`;
904+
// `lean_apply_n` dispatches on `m` and consumes `f`.
905+
new_f = lean_apply_n(f, m, as);
906+
}
907+
return lean_apply_n(new_f, n - m, &as[m]);
899908
} else {
900909
return fix_args(f, n, as);
901910
}

0 commit comments

Comments
 (0)