Tatopenn commited on
Commit
95ce85d
·
verified ·
1 Parent(s): 5cae743

Sync test_dense_evolution.py from v8.1.35

Browse files
Files changed (1) hide show
  1. test_dense_evolution.py +27 -4
test_dense_evolution.py CHANGED
@@ -1203,19 +1203,26 @@ class TestParserEvalSecurity:
1203
 
1204
  @pytest.mark.parametrize('payload', _ESCAPE_PAYLOADS)
1205
  def test_eval_param_blocks_sandbox_escapes(self, payload):
1206
- assert QASMParser()._eval_param(payload) == 0.0
 
 
 
 
 
 
 
1207
 
1208
  @pytest.mark.parametrize('payload', _ESCAPE_PAYLOADS)
1209
  def test_resolve_int_expr_blocks_sandbox_escapes(self, payload):
1210
  assert QASMParser()._resolve_int_expr(payload, {}) is None
1211
 
1212
- def test_original_exploit_through_full_parse_returns_silent_zero(self):
1213
  # end-to-end through the actual public entry point, not just the
1214
  # internal method directly
1215
  qasm = ('OPENQASM 3.0; qubit[1] q; '
1216
  'rx(().__class__.__bases__[0].__subclasses__().__len__()) q[0];')
1217
- circ = QASMParser().parse(qasm)
1218
- assert circ.ops[0]['params'] == [0.0]
1219
 
1220
  def test_original_exploit_in_for_loop_bound_yields_no_ops(self):
1221
  qasm = ('OPENQASM 3.0; qubit[1] q; '
@@ -1234,6 +1241,22 @@ class TestParserEvalSecurity:
1234
  def test_legitimate_expressions_unchanged(self, expr, expected):
1235
  assert QASMParser()._eval_param(expr) == pytest.approx(expected)
1236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1237
  def test_legitimate_for_loop_bounds_unchanged(self):
1238
  qasm = 'qreg q[3]; int n = 3; for int i in [0:n-1] { x q[i]; }'
1239
  circ = QASMParser().parse(qasm)
 
1203
 
1204
  @pytest.mark.parametrize('payload', _ESCAPE_PAYLOADS)
1205
  def test_eval_param_blocks_sandbox_escapes(self, payload):
1206
+ # _eval_param used to swallow every rejected expression into a
1207
+ # silent 0.0 (same fallback a genuine typo like 'pi * / 2' hit
1208
+ # too); it now raises ValueError instead -- still structurally
1209
+ # blocked (the AST whitelist never reaches these nodes), just
1210
+ # explicit about it instead of silent, same as a malformed
1211
+ # expression from a typo.
1212
+ with pytest.raises(ValueError):
1213
+ QASMParser()._eval_param(payload)
1214
 
1215
  @pytest.mark.parametrize('payload', _ESCAPE_PAYLOADS)
1216
  def test_resolve_int_expr_blocks_sandbox_escapes(self, payload):
1217
  assert QASMParser()._resolve_int_expr(payload, {}) is None
1218
 
1219
+ def test_original_exploit_through_full_parse_raises(self):
1220
  # end-to-end through the actual public entry point, not just the
1221
  # internal method directly
1222
  qasm = ('OPENQASM 3.0; qubit[1] q; '
1223
  'rx(().__class__.__bases__[0].__subclasses__().__len__()) q[0];')
1224
+ with pytest.raises(ValueError):
1225
+ QASMParser().parse(qasm)
1226
 
1227
  def test_original_exploit_in_for_loop_bound_yields_no_ops(self):
1228
  qasm = ('OPENQASM 3.0; qubit[1] q; '
 
1241
  def test_legitimate_expressions_unchanged(self, expr, expected):
1242
  assert QASMParser()._eval_param(expr) == pytest.approx(expected)
1243
 
1244
+ @pytest.mark.parametrize('malformed', [
1245
+ 'pi * / 2', 'pi +', '(pi', 'pi 2', '**pi', 'pi // 2',
1246
+ ])
1247
+ def test_malformed_expression_raises_instead_of_silent_zero(self, malformed):
1248
+ # Found via an external code-review report, reproduced directly:
1249
+ # 'rx(pi * / 2) q[0];' used to parse successfully and silently
1250
+ # produce rx(0.0) -- a different, valid circuit, no signal a typo
1251
+ # happened. Now raises instead of hiding the mistake.
1252
+ with pytest.raises(ValueError):
1253
+ QASMParser()._eval_param(malformed)
1254
+
1255
+ def test_malformed_expression_through_full_parse_raises(self):
1256
+ qasm = 'OPENQASM 2.0; include "qelib1.inc"; qreg q[1]; rx(pi * / 2) q[0];'
1257
+ with pytest.raises(ValueError):
1258
+ QASMParser().parse(qasm)
1259
+
1260
  def test_legitimate_for_loop_bounds_unchanged(self):
1261
  qasm = 'qreg q[3]; int n = 3; for int i in [0:n-1] { x q[i]; }'
1262
  circ = QASMParser().parse(qasm)