Skip to content

[python] Kernel with a return only inside a dynamic-bound loop compiles without a return-type check #5369

Description

@udsy19

Required prerequisites

  • Consult the security policy. Not a security report.
  • Read the documentation; this isn't addressed there.
  • Searched the issue tracker; found nothing on this.
  • PR attached with a failing test.

Describe the bug

ValidateReturnStatements.all_paths_return (python/cudaq/kernel/analysis.py:191-206), the
compile-time check behind cudaq.kernel functions with return type annotations must have a return statement., treats a for/while loop as guaranteeing a return whenever its body
alone always returns, independent of whether the loop is ever entered:

if isinstance(stmt, (ast.For, ast.While)):
    if all_paths_return(stmt.body) or all_paths_return(
            stmt.orelse):
        return True

For a loop whose trip count is a runtime value (for i in range(n):, while i < n:), this is
unsound: if the loop executes zero times, control falls off the end of the function with no
return statement ever having run, and the fatal error is never raised. The kernel compiles
successfully and the backend's cc.UndefOp fallback (ast_bridge.py's visit_FunctionDef
entry-block finalization) silently manufactures whatever value happens to be returned instead.

Steps to reproduce the bug

import cudaq

@cudaq.kernel
def kernel(n: int) -> int:
    for i in range(n):
        return 1
    # falls through here when n <= 0, with no return statement having executed

print("compiled without error")           # should have raised RuntimeError
print(cudaq.run(kernel, 0, shots_count=1)) # returns a value with no defined meaning

The sibling ast.If check just above is written correctly, requiring both branches to
return (all_paths_return(stmt.body) and all_paths_return(stmt.orelse)); the loop check uses
or instead, which is the bug.

What did you expect to happen?

Compilation should raise RuntimeError: cudaq.kernel functions with return type annotations must have a return statement., exactly as it already does for the equivalent case where the
loop body only conditionally returns (e.g. for i in range(n): if i == 0: return 1, already
covered by test_return_from_if_and_else_loop_having_for_with_no_return).

Environment

Reproduced against the installed cuda_quantum_cu13 0.15.1 wheel
(aca5853a76d499ecc3d5f97c2e06163ae99d9c75) on Linux/Python 3.12; python/cudaq/kernel/analysis.py
is byte-identical between that wheel and current main
(00536511e91775ca829e4fa816663e1618edb185), confirmed via git log <wheel-sha>..main -- python/cudaq/kernel/analysis.py (empty) and a direct diff.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    stale-notifiedStale notification has already fired for this issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions