Skip to content

Fix IndexError in cast_inputs for ops with no formal inputs - #3045

Open
bodapatisaikrishna wants to merge 1 commit into
microsoft:mainfrom
bodapatisaikrishna:fix/cast-inputs-empty-signature-indexerror
Open

Fix IndexError in cast_inputs for ops with no formal inputs#3045
bodapatisaikrishna wants to merge 1 commit into
microsoft:mainfrom
bodapatisaikrishna:fix/cast-inputs-empty-signature-indexerror

Conversation

@bodapatisaikrishna

Copy link
Copy Markdown

Motivation

autocast.cast_inputs() is the shared implementation behind both eager-mode
execution (dynamic_cast_inputs) and static script-translation
(static_cast_inputs). When it sees more positional arguments than the op's
formal input parameters, it's supposed to raise a clear error:

raise ValueError(
    f"Number of actual parameters {len(args)} "
    f"exceeds number of formal parameters {len(expected_inputs)}."
)

But the branch that decides whether to raise that error indexes into
expected_inputs[-1] unconditionally:

if i < len(expected_inputs):
    expected = expected_inputs[i]
elif expected_inputs[-1].variadic:   # <-- IndexError when expected_inputs == []
    ...
else:
    raise ValueError(...)

For an op with zero formal input parameters (only attributes — e.g.
RandomNormal, RandomUniform), expected_inputs is [], so
expected_inputs[-1] raises an unhandled IndexError: list index out of range instead of the intended ValueError.

This is reachable end-to-end through values.Op.__call__, which doesn't
pre-validate argument counts before dispatching to
evaluator.eval_op -> autocast.dynamic_cast_inputs -> cast_inputs. This
path is used for any op accessed dynamically (e.g. custom-domain ops via
Opset.__getattr__, or an Op constructed directly), as opposed to the
code-generated opset functions (e.g. opset18.RandomNormal), which have
fixed Python signatures that Python itself rejects extra arguments for.

Repro:

from onnxscript._internal import values
from onnxscript import opset18

values.Op(opset18, "RandomNormal")(1.0, 2.0, 3.0)
# IndexError: list index out of range

Fix

Guard the variadic check with expected_inputs and ... so an empty input
list falls through to the existing else branch and raises the intended,
descriptive ValueError instead of crashing with an unrelated IndexError.
One-line change; no other behavior affected — the non-empty variadic and
non-variadic paths are untouched.

Testing

Added onnxscript/_internal/autocast_test.py (no test file existed for this
module) covering:

  • the empty-formal-inputs overflow case (was IndexError, now ValueError)
  • the empty-formal-inputs no-args case (still returns (), no regression)
  • the pre-existing non-variadic overflow case (still raises ValueError)
  • the homogeneous-variadic case (guards against regressing the condition
    just touched)
$ python -m pytest onnxscript/_internal/autocast_test.py -q
4 passed
$ python -m pytest onnxscript/_internal/ -q
188 passed, 1 skipped, 1 xfailed, 3 xpassed

Confirmed the new failing-case test fails with the original IndexError
when the fix is reverted (git stash), and passes with the fix applied.

ruff check / ruff format --check clean on both changed files.

Found by reading autocast.py and testing cast_inputs against its own
error-message contract, not from a reported issue.

autocast.cast_inputs() checks expected_inputs[-1].variadic to decide
whether extra positional arguments can be absorbed by a trailing
variadic parameter. When op_signature.inputs is empty (an op with no
formal input parameters, e.g. RandomNormal, which only has
attributes), this indexes into an empty list and raises an
unhandled IndexError instead of the intended ValueError with a clear
message.

Reproducible end-to-end via the generic Op.__call__ dispatch path
(values.Op), which does not pre-validate positional-argument count
before calling autocast.dynamic_cast_inputs -> cast_inputs:

    from onnxscript._internal import values
    from onnxscript import opset18
    values.Op(opset18, 'RandomNormal')(1.0, 2.0, 3.0)
    # IndexError: list index out of range

Guard the variadic check with 'expected_inputs and ...' so an empty
input list falls through to the existing else branch and raises the
intended ValueError('Number of actual parameters ... exceeds number
of formal parameters ...') instead.

Added onnxscript/_internal/autocast_test.py covering: the empty-input
error case, the empty-input no-args case, the existing
non-variadic-overflow case, and the homogeneous-variadic case (to
guard against regressing the condition just touched).
@bodapatisaikrishna

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant