|
5 | 5 | import copy |
6 | 6 | import ctypes |
7 | 7 | import gc |
| 8 | +import importlib.util |
8 | 9 | import os |
9 | 10 | import pathlib |
10 | 11 | import platform |
@@ -1514,29 +1515,32 @@ def test_ort_value_array_protocol(self): |
1514 | 1515 | np.testing.assert_equal(bool_arr, result_bool) |
1515 | 1516 | self.assertEqual(result_bool.dtype, np.bool_) |
1516 | 1517 |
|
| 1518 | + @unittest.skipUnless( |
| 1519 | + importlib.util.find_spec("onnx") is not None, |
| 1520 | + "onnx package is required to build the test model", |
| 1521 | + ) |
1517 | 1522 | def test_run_output_does_not_alias_input_passthrough(self): |
1518 | 1523 | """Test that session.run() returns independent numpy arrays when a model |
1519 | 1524 | input passes through as a model output. Reproduces the dangling-pointer |
1520 | 1525 | corruption described in https://github.com/microsoft/onnxruntime/issues/21922 |
1521 | 1526 | """ |
1522 | 1527 | import onnx # noqa: PLC0415 |
1523 | | - from onnx import TensorProto, helper # noqa: PLC0415 |
1524 | 1528 |
|
1525 | 1529 | # Build a model where 'input_0' is both a graph input and a graph output, |
1526 | 1530 | # plus a computed output (input_0 + 10). |
1527 | 1531 | inp_shape = [1, 2, 2, 2] |
1528 | | - input_0 = helper.make_tensor_value_info("input_0", TensorProto.FLOAT, inp_shape) |
1529 | | - output_plus10 = helper.make_tensor_value_info("plus_10", TensorProto.FLOAT, inp_shape) |
| 1532 | + input_0 = onnx.helper.make_tensor_value_info("input_0", onnx.TensorProto.FLOAT, inp_shape) |
| 1533 | + output_plus10 = onnx.helper.make_tensor_value_info("plus_10", onnx.TensorProto.FLOAT, inp_shape) |
1530 | 1534 | ten_const = onnx.numpy_helper.from_array(np.array(10, dtype=np.float32), "ten_const") |
1531 | | - add_node = helper.make_node("Add", ["input_0", "ten_const"], ["plus_10"], name="Add0") |
1532 | | - graph = helper.make_graph( |
| 1535 | + add_node = onnx.helper.make_node("Add", ["input_0", "ten_const"], ["plus_10"], name="Add0") |
| 1536 | + graph = onnx.helper.make_graph( |
1533 | 1537 | [add_node], |
1534 | 1538 | "PassthroughTest", |
1535 | 1539 | [input_0], |
1536 | 1540 | [output_plus10, input_0], |
1537 | 1541 | initializer=[ten_const], |
1538 | 1542 | ) |
1539 | | - model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 21)]) |
| 1543 | + model = onnx.helper.make_model(graph, opset_imports=[onnx.helper.make_opsetid("", 21)]) |
1540 | 1544 | model = onnx.shape_inference.infer_shapes(model) |
1541 | 1545 |
|
1542 | 1546 | sess_options = onnxrt.SessionOptions() |
@@ -1567,6 +1571,10 @@ def test_run_output_does_not_alias_input_passthrough(self): |
1567 | 1571 |
|
1568 | 1572 | # The pass-through output must NOT alias the input buffer — |
1569 | 1573 | # it must be an independent copy so it survives across runs. |
| 1574 | + self.assertFalse( |
| 1575 | + np.shares_memory(outputs[1], input_data), |
| 1576 | + f"Run {run_index}: 'input_0' unexpectedly aliases the input buffer", |
| 1577 | + ) |
1570 | 1578 | all_run_outputs.append(outputs) |
1571 | 1579 |
|
1572 | 1580 | # After all runs, every saved output must still hold its original value. |
|
0 commit comments