Skip to content

Fix Failure("nth") crash in remove_unused_parameters#678

Open
elefthei wants to merge 3 commits intomasterfrom
fix/nth-crash-unused-params
Open

Fix Failure("nth") crash in remove_unused_parameters#678
elefthei wants to merge 3 commits intomasterfrom
fix/nth-crash-unused-params

Conversation

@elefthei
Copy link

Fixes #677

Problem

remove_unused_parameters in lib/Simplify.ml crashes with Failure("nth") when bundling modules where a function call site has more actual arguments than the callee's formal type parameters (as reported by flatten_arrow).

This happens when erased/ghost parameters are passed as () at call sites, but the callee's type signature doesn't include them (e.g., external functions like Pulse.Lib.Array.PtsTo.op_Array_Access whose ghost args were erased from the type but not from call sites).

Root Cause

In unused_i (line 236), List.nth ts i = TUnit is called without bounds checking. The update_table_current call at line 344 in visit_EApp iterates over actual arguments es and calls unused arg_i for each — but arg_i can exceed List.length ts when there are more actual args than formal type params. The length guard at line 353 correctly handles this for the main transformation path, but update_table_current is invoked before that guard.

Fix

Add a bounds check so unused_i returns false for out-of-bounds indices (conservative: don't eliminate unknown params):

-    List.nth ts i = TUnit
+    i < List.length ts && List.nth ts i = TUnit

Reproduction

Extract a Pulse module with .fsti interface (making implementations private), create a wrapper without .fsti, and bundle them:

krml -bundle 'Wrapper=Wrapper,Lib,Lib.Spec' Wrapper.krml Lib.krml Lib_Spec.krml
# Fatal error: exception Failure("nth")

After the fix, extraction succeeds and produces correct C output with all functions.

In unused_i (lib/Simplify.ml line 236), List.nth ts i was called without
bounds checking. When update_table_current iterates over actual arguments
(es) of an EApp whose callee has fewer formal type parameters than actual
arguments (e.g. erased ghost params passed as () at call sites), i can
exceed List.length ts, causing a Failure("nth") crash.

The length guard at line 353 (if List.length es <= List.length ts) handles
this for the main transformation, but update_table_current is called before
that guard at line 344.

Add a bounds check so unused_i returns false for out-of-bounds indices,
which is the correct conservative behavior (don't eliminate unknown params).

Fixes #677
@protz
Copy link
Collaborator

protz commented Feb 11, 2026

  • Are you doing separate extraction and compilation, or are we talking about a single run of krml?
  • Can you show a complete example with the contents of Wrapper, Lib and Lib.Spec?
    Thanks

@protz
Copy link
Collaborator

protz commented Feb 17, 2026

@tahina-pro is this something you can help with? I would love for this PR to have a corresponding regression in the test suite, which would allow me to understand the problem -- right now, without a supporting example, it's hard to determine whether this is the right fix or not

@elefthei
Copy link
Author

@protz hey sorry for dropping the ball this week is kind of busy. I will add a repro Friday

Lef Ioannidis and others added 2 commits February 18, 2026 06:31
Add a JSON-based test (test/json/NthCrash.json) that reproduces the crash
from #677: a DExternal2 with more hint names than type arrows triggers an
out-of-bounds List.nth in unused_i when visit_DExternal iterates hints.

This test crashes on master with Failure("nth") and succeeds with the fix.

Introduces test/json/ as a new test subdirectory for JSON-encoded karamel
AST inputs, with its own Makefile and a json-test target in test/Makefile.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

remove_unused_parameters crashes with Failure("nth") when EApp has more arguments than callee type arrow

2 participants