Skip to content

Commit

Permalink
Test deserializer on infinite recursion. (quantumlib#4315)
Browse files Browse the repository at this point in the history
Fixes quantumlib#4304.

To be precise, this was already working: because the deserializer does not append constants to the `deserialized_constants` map until it finishes deserializing them, it is naturally unable to deserialize a recursive subcircuit. This PR just adds the test.

Note that the _serializer_ will still happily attempt (and fail) to serialize CircuitOperations that exhibit infinite recursion. We allow this because `CircuitOperation` is an immutable type; unless you intentionally circumvent the safeguards that prevent mutation (as shown in the test), it is not possible to define a `CircuitOperation` that contains itself.
  • Loading branch information
95-martin-orion authored and rht committed May 1, 2023
1 parent 91239f0 commit 91139f3
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions cirq-google/cirq_google/serializable_gate_set_test.py
Expand Up @@ -293,6 +293,48 @@ def test_serialize_deserialize_circuit_with_subcircuit():
assert MY_GATE_SET.deserialize(proto) == circuit


def test_deserialize_infinite_recursion_fails():
inf_op = cirq.CircuitOperation(cirq.FrozenCircuit())
# Maliciously modify the CircuitOperation to be self-referencing.
setattr(inf_op.circuit, '_moments', tuple(cirq.Circuit(inf_op).moments))
circuit = cirq.Circuit(inf_op)
with pytest.raises(RecursionError):
_ = MY_GATE_SET.serialize(circuit)

c_op1 = v2.program_pb2.CircuitOperation()
c_op1.circuit_constant_index = 0
rep_spec = c_op1.repetition_specification
rep_spec.repetition_count = 2
rep_spec.repetition_ids.ids.extend(['a', 'b'])

# This proto is illegal: c_op1 references a constant containing c_op1.
proto = v2.program_pb2.Program(
language=v2.program_pb2.Language(arg_function_language='', gate_set='my_gate_set'),
circuit=v2.program_pb2.Circuit(
scheduling_strategy=v2.program_pb2.Circuit.MOMENT_BY_MOMENT,
moments=[
v2.program_pb2.Moment(
circuit_operations=[c_op1],
),
],
),
constants=[
v2.program_pb2.Constant(
circuit_value=v2.program_pb2.Circuit(
scheduling_strategy=v2.program_pb2.Circuit.MOMENT_BY_MOMENT,
moments=[
v2.program_pb2.Moment(
circuit_operations=[c_op1],
),
],
)
),
],
)
with pytest.raises(ValueError, match="Failed to deserialize circuit"):
_ = MY_GATE_SET.deserialize(proto)


def test_deserialize_bad_operation_id():
proto = v2.program_pb2.Program(
language=v2.program_pb2.Language(arg_function_language='', gate_set='my_gate_set'),
Expand Down

0 comments on commit 91139f3

Please sign in to comment.