Validate 'num_scan_inputs' attribute in Scan kernel construction (#31668)
### Description
The `Scan` operator's `num_scan_inputs` attribute determines how many of
the node's variadic inputs are scan inputs (the remainder are loop state
variables). In `scan::detail::Info::Info` (shared by the CPU
`Scan-8`/`Scan-9` kernels, and reused as-is by the CUDA `Scan` kernel),
this attribute was used in two unguarded subtractions:
```cpp
num_loop_state_variables = num_variadic_inputs - num_scan_inputs;
...
num_scan_outputs = num_outputs - num_loop_state_variables;
```
If `num_scan_inputs` is outside `[0, num_variadic_inputs]`,
`num_loop_state_variables` becomes negative. That value is later used,
unguarded, as a loop-start index into the node's inputs during
`Compute()`, resulting in out-of-range indexing.
This PR adds validation of `num_scan_inputs` (and the derived
`num_loop_state_variables`) in the constructor, rejecting invalid values
up front with a clear error message before any arithmetic derived from
them is used for indexing.
### Testing
Added regression tests for both opset 8 and opset 9+ with an
out-of-range `num_scan_inputs` value:
- Opset 8 hits the new kernel-construction-time check directly.
- Opset 9+ is caught earlier during graph resolution's standard
ONNX-level shape inference (before the kernel is even constructed), so
its test asserts on the shape-inference error message instead.
Both tests are guarded by `#if !defined(ORT_NO_EXCEPTIONS)` since they
rely on exception-based failure reporting.
Ran locally (CPU-only Debug build):
- `onnxruntime_provider_test --gtest_filter='Scan*'` — all 34 tests
pass, including the 2 new ones.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 77dcaf1b-748a-4379-94a7-478f7a924d73