Skip to content

Commit 26b8b8b

Browse files
authored
Avoid segfault in ExecutionContext.__exit__ when kernel throws (#4066)
When a kernel raises inside a with ExecutionContext block (cudaq.observe called with a list argument that is too short), the __exit__ exception was still calling platform.finalizeExecutionContext(). On the custatevec GPU backend this triggers an API call against an uninitialized simulator state, causing a segfault. Update: Have put back the `finalizeExecutionContext` in __exit__ and handling the 0 allocated qubits inside simulator. Found second issue. When there are 0 qubit allocated, calling setToZeroState (in endExecution) on an unitialized GPU state causes segfault as was evident from the failing jobs in the first run of this PR. Adding a fix to handle a case for the observe path via handleObservation. Fixes #4062 --------- Signed-off-by: Sachin Pisal <spisal@nvidia.com>
1 parent 91c5729 commit 26b8b8b

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

python/tests/builder/test_observe.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,38 @@ def test_observe_numpy_array(angles, want_state, want_expectation):
576576
cudaq.observe(kernel, hamiltonian, bad_params, qpu_id=0, shots_count=10)
577577

578578

579+
def test_observe_kernel_exception_no_segfault():
580+
"""
581+
When cudaq.observe is called with list arguments that are
582+
too short, the kernel raises a RuntimeError inside the ExecutionContext.
583+
Before this change, ExecutionContext.__exit__ would call finalizeExecutionContext on
584+
an uninitialized simulator state causing a segfault on GPU backend.
585+
"""
586+
qubit_count = 4
587+
kernel, thetas = cudaq.make_kernel(list)
588+
qreg = kernel.qalloc(qubit_count)
589+
for i in range(qubit_count):
590+
kernel.rx(thetas[i], qreg[i])
591+
hamiltonian = spin.z(0) + spin.z(1) + spin.z(2) + spin.z(3)
592+
593+
with pytest.raises(Exception) as exception:
594+
cudaq.observe(kernel,
595+
hamiltonian,
596+
np.random.uniform(size=(3, 2)),
597+
shots_count=10)
598+
assert "Invalid runtime list argument" in str(exception.value)
599+
600+
with pytest.raises(Exception) as exception:
601+
cudaq.observe(kernel,
602+
hamiltonian,
603+
np.random.uniform(size=(2,)),
604+
shots_count=10)
605+
assert "Invalid runtime list argument" in str(exception.value)
606+
607+
result = cudaq.observe(kernel, hamiltonian, [np.pi] * qubit_count)
608+
assert np.isclose(result.expectation(), -4.0, atol=1e-12)
609+
610+
579611
def test_observe_n():
580612
"""
581613
Test that we can broadcast the observe call over a number of argument sets

runtime/nvqir/CircuitSimulator.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,9 @@ class CircuitSimulatorBase : public CircuitSimulator {
966966

967967
/// @brief Reset the current execution context.
968968
void finalizeExecutionContext(cudaq::ExecutionContext &context) override {
969+
if (nQubitsAllocated == 0 && context.name != "sample")
970+
return;
971+
969972
// Get the ExecutionContext name
970973
auto execContextName = context.name;
971974

@@ -1045,6 +1048,11 @@ class CircuitSimulatorBase : public CircuitSimulator {
10451048

10461049
/// @brief Clean up state after execution ends
10471050
void endExecution() override {
1051+
if (nQubitsAllocated == 0) {
1052+
tracker = {};
1053+
return;
1054+
}
1055+
10481056
bool shouldSetToZero = cudaq::isInBatchMode() && !cudaq::isLastBatch();
10491057

10501058
// Reset the state if we've deallocated all qubits.
@@ -1286,6 +1294,12 @@ class CircuitSimulatorBase : public CircuitSimulator {
12861294
void measureSpinOp(const cudaq::spin_op &op) override {
12871295
auto executionContext = cudaq::getExecutionContext();
12881296

1297+
if (nQubitsAllocated == 0) {
1298+
if (executionContext)
1299+
executionContext->expectationValue = 0.0;
1300+
return;
1301+
}
1302+
12891303
flushGateQueue();
12901304

12911305
if (executionContext->canHandleObserve) {

0 commit comments

Comments
 (0)