Menu

#858 ngspice's getopt_long silently eats unrecognised script params

v1.0 (example)
open
nobody
None
5
2026-08-09
2026-08-09
No

ngspice vlnggen --trace counter.v → stderr warning, rc=0, script sees argc=1, non-trace build reported as success. Escape: ngspice -- vlnggen --trace counter.v. Affects anyone using the documented trace flow.

Discussion

  • ananthsforge

    ananthsforge - 2026-08-09

    found by Claude Code

     
  • ananthsforge

    ananthsforge - 2026-08-09

    From Claude :

    *ng_script_with_params scripts silently lose any parameter that looks like an unknown option

    Version: 46 (release) and 46+ (master, 65efb6ee9)
    OS: Ubuntu 24.04.4, x86-64
    Severity: silent wrong result — breaks the documented vlnggen --trace flow

    Summary

    Parameters passed to a *ng_script_with_params script are taken from Copy_of_argv[optind…], which is populated after getopt_long() has already consumed the command line. Any parameter beginning with - that ngspice does not recognise is reported on stderr and then dropped: the script never sees it, and nothing tells the script that an argument went missing.

    Reproduction

    $ cat > p.sp <<'EOF'
    *ng_script_with_params
    echo argc=$argc
    echo argv=$argv
    quit
    EOF

    $ ngspice p.sp --trace counter.v
    ngspice: unrecognized option '--trace'
    argc=1
    argv=counter.v # <-- --trace is gone

    $ ngspice -- p.sp --trace counter.v
    argc=2
    argv=--trace counter.v # <-- correct

    Argument order does not help: ngspice p.sp counter.v --trace also yields argc=1.

    Why it matters

    vlnggen is a *ng_script_with_params script whose entire interface is "arguments acceptable to Verilator". The documented way to request a waveform-capable code model is therefore ngspice vlnggen --trace foo.v, and that command silently produces a non-trace build that exits 0:

    g++ ... -DVM_TRACE=0 -DVM_TRACE_VCD=0 ... -c -o Vlng__ALL.o Vlng__ALL.cpp

    The user gets a .so with no tracing, no error from the script, and only a stderr line from ngspice itself mentioning an option the script never asked about.

    Cause

    src/main.c:1489 assigns Copy_of_argv = argv inside the *ng_script_with_params branch, i.e. after option parsing. src/frontend/inp.c:665-690 then builds the script's argv from Copy_of_argv[optind + n]. GNU getopt_long() has already skipped unrecognised options and does not leave them in the [optind, argc) range, so they are unreachable by construction.

    Suggested fixes (any one)

    1. Snapshot argv before getopt_long() runs and hand the script everything after the script filename verbatim.
    2. Stop permutation for this case — a leading + in the optstring, or opterr = 0 plus explicit handling.
    3. Minimum viable: document the -- escape in the vlnggen/ghnggen header comments and in the manual, and make vlnggen fail loudly when it receives no verilator options beyond the .v file.
     

Log in to post a comment.