Skip to content

Fix command line parsing in the cuda.bindings example helpers - #2546

Open
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:example-helpers-cmd-line-args
Open

Fix command line parsing in the cuda.bindings example helpers#2546
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:example-helpers-cmd-line-args

Conversation

@LeSingh1

@LeSingh1 LeSingh1 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Both helpers in cuda/bindings/_example_helpers/helper_string.py unpack enumerate()
backwards:

def check_cmd_line_flag(string_ref):
    return any(string_ref == i and k < len(sys.argv) - 1 for i, k in enumerate(sys.argv))


def get_cmd_line_argument_int(string_ref):
    for i, k in enumerate(sys.argv):
        if string_ref == i and k < len(sys.argv) - 1:
            return sys.argv[k + 1]
    return 0

enumerate() yields (index, value), so i is an int and k is a str — but the
body uses i as the argument text and k as the index. string_ref == i compares str
to int and is therefore always False.

$ python -c "from cuda.bindings._example_helpers import check_cmd_line_flag, get_cmd_line_argument_int; \
             print(check_cmd_line_flag('device='), get_cmd_line_argument_int('device='))" device= 3
False 0

So check_cmd_line_flag() always returns False and get_cmd_line_argument_int() always
returns 0. Every command line option in the examples is silently ignored — device=,
wA=, hA=, wB=, hB=, kernel=, help, ?, use_generic_memory — reaching
helper_cuda.find_cuda_device() / find_cuda_device_drv(),
3_CUDA_Features/global_to_shmem_async_copy.py, 0_Introduction/simple_zero_copy.py
and 2_Concepts_and_Techniques/stream_ordered_allocation.py.

Note the dead branch would not have worked either: k < len(sys.argv) - 1 is str < int
(TypeError) and sys.argv[k + 1] indexes with a str. Nothing here has ever run.

Three judgement calls, since "the current behaviour" is not a guide

Because both functions are constant today, any fix defines new behaviour. I kept it as
close to the evident intent — and to the C samples' helper_string.h — as I could:

  1. check_cmd_line_flag() no longer requires a following argument. That condition
    belongs to the value lookup. Keeping it would leave help and ? broken whenever they
    are the last argument, which is the normal way to pass them.
  2. Both helpers skip sys.argv[0], matching checkCmdLineFlag() in the C samples,
    which scans from argv[1].
  3. get_cmd_line_argument_int() returns an int, as its name says and as its callers
    require: helper_cuda.find_cuda_device() passes the result straight to
    cudaSetDevice() and find_cuda_device_drv() to cuDeviceGet(). Returning
    sys.argv[idx + 1] unchanged would hand those APIs a str — i.e. fixing only the
    unpacking would turn a silent no-op into a TypeError. An int is also the only value
    this function has ever actually returned, since the literal 0 fallback was the sole
    reachable path.

Happy to change any of these if you'd prefer different semantics.

Tests

New cuda_bindings/tests/test_example_helpers.py — pure sys.argv monkeypatching, no GPU
or toolkit needed. Five of its assertions fail against upstream/main (flag present,
trailing boolean flag, flag in the middle of a longer argv, and both value lookups); the
program-name and not-found cases pass either way and are there to pin the new edges down.

tests/test_examples.py runs each example in a subprocess as [sys.executable, example],
so sys.argv[1:] is empty there and no flag can accidentally match under pytest.

Verified against upstream/main and with the change; ruff check and
ruff format --check are clean.

Both helpers unpack enumerate() backwards:

    def check_cmd_line_flag(string_ref):
        return any(string_ref == i and k < len(sys.argv) - 1 for i, k in enumerate(sys.argv))

enumerate() yields (index, value), so `i` is an int and `k` is a str, but the
body uses `i` as the argument text and `k` as the index. `string_ref == i`
compares str to int and is therefore always False:

    $ python -c "import sys; from cuda.bindings._example_helpers import *; \
                 print(check_cmd_line_flag('device='), get_cmd_line_argument_int('device='))" device= 3
    False 0

check_cmd_line_flag() always returns False and get_cmd_line_argument_int()
always returns 0, so every command line option in the examples is silently
ignored: device=, wA=, hA=, wB=, hB=, kernel=, help, ? and
use_generic_memory, via helper_cuda.find_cuda_device(),
find_cuda_device_drv(), global_to_shmem_async_copy.py,
simple_zero_copy.py and stream_ordered_allocation.py. The dead branch would
not have worked either: `k < len(sys.argv) - 1` is str < int (TypeError) and
`sys.argv[k + 1]` indexes with a str.

Alongside the unpacking:

- check_cmd_line_flag() no longer requires a following argument. That
  condition belongs to the value lookup; requiring it would keep `help` and
  `?` broken whenever they are the last argument, which is the normal way to
  pass them.
- Both helpers skip sys.argv[0], matching the C samples' helper_string.h,
  which scans from argv[1].
- get_cmd_line_argument_int() returns an int, as its name says and as its
  callers require: helper_cuda.find_cuda_device() passes the result straight
  to cudaSetDevice(), and find_cuda_device_drv() to cuDeviceGet(). Returning
  sys.argv[k + 1] unchanged would hand those APIs a str. This is also the
  only value the function has ever actually returned, since the literal 0
  fallback was the sole reachable path.

Adds cuda_bindings/tests/test_example_helpers.py. Five of its assertions
fail against main.
@copy-pr-bot

copy-pr-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added the cuda.bindings Everything related to the cuda.bindings module label Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cuda.bindings Everything related to the cuda.bindings module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant