angr 9.2.138__py3-none-macosx_11_0_arm64.whl → 9.2.139__py3-none-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (59) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention/fact_collector.py +59 -12
  3. angr/analyses/calling_convention/utils.py +2 -2
  4. angr/analyses/cfg/cfg_fast.py +12 -4
  5. angr/analyses/decompiler/ail_simplifier.py +14 -3
  6. angr/analyses/decompiler/block_simplifier.py +0 -2
  7. angr/analyses/decompiler/callsite_maker.py +80 -14
  8. angr/analyses/decompiler/clinic.py +31 -37
  9. angr/analyses/decompiler/condition_processor.py +2 -2
  10. angr/analyses/decompiler/decompiler.py +2 -0
  11. angr/analyses/decompiler/dephication/rewriting_engine.py +16 -7
  12. angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
  13. angr/analyses/decompiler/optimization_passes/condition_constprop.py +149 -0
  14. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +12 -3
  15. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +1 -1
  16. angr/analyses/decompiler/optimization_passes/optimization_pass.py +5 -2
  17. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +15 -7
  18. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +7 -10
  19. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +12 -1
  20. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +61 -25
  21. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +50 -1
  22. angr/analyses/decompiler/presets/fast.py +2 -0
  23. angr/analyses/decompiler/presets/full.py +2 -0
  24. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +4 -0
  25. angr/analyses/decompiler/ssailification/rewriting_engine.py +20 -2
  26. angr/analyses/decompiler/ssailification/traversal_engine.py +4 -3
  27. angr/analyses/decompiler/structured_codegen/c.py +10 -3
  28. angr/analyses/decompiler/structuring/dream.py +7 -2
  29. angr/analyses/decompiler/structuring/phoenix.py +101 -49
  30. angr/analyses/decompiler/structuring/structurer_base.py +85 -36
  31. angr/analyses/decompiler/structuring/structurer_nodes.py +3 -1
  32. angr/analyses/deobfuscator/api_obf_finder.py +6 -1
  33. angr/analyses/deobfuscator/api_obf_type2_finder.py +158 -0
  34. angr/analyses/s_propagator.py +127 -50
  35. angr/analyses/s_reaching_definitions/s_rda_view.py +2 -2
  36. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -1
  37. angr/analyses/variable_recovery/engine_ail.py +1 -1
  38. angr/analyses/variable_recovery/engine_base.py +55 -62
  39. angr/analyses/variable_recovery/engine_vex.py +1 -1
  40. angr/analyses/variable_recovery/irsb_scanner.py +2 -2
  41. angr/calling_conventions.py +66 -9
  42. angr/engines/engine.py +2 -18
  43. angr/engines/light/engine.py +3 -8
  44. angr/engines/pcode/emulate.py +2 -2
  45. angr/engines/pcode/lifter.py +2 -2
  46. angr/engines/successors.py +1 -8
  47. angr/engines/vex/lifter.py +2 -2
  48. angr/engines/vex/light/light.py +2 -2
  49. angr/knowledge_plugins/cfg/cfg_model.py +3 -2
  50. angr/knowledge_plugins/labels.py +2 -2
  51. angr/knowledge_plugins/obfuscations.py +1 -0
  52. angr/knowledge_plugins/xrefs/xref_manager.py +4 -0
  53. angr/lib/angr_native.dylib +0 -0
  54. {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/METADATA +6 -6
  55. {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/RECORD +59 -57
  56. {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/LICENSE +0 -0
  57. {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/WHEEL +0 -0
  58. {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/entry_points.txt +0 -0
  59. {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/top_level.txt +0 -0
@@ -4,9 +4,9 @@ from typing import Any
4
4
 
5
5
  import networkx
6
6
 
7
+ from angr.analyses.decompiler.structuring import SAILRStructurer, DreamStructurer
7
8
  from .return_duplicator_base import ReturnDuplicatorBase
8
9
  from .optimization_pass import OptimizationPass, OptimizationPassStage
9
- from angr.analyses.decompiler.structuring import SAILRStructurer, DreamStructurer
10
10
 
11
11
  _l = logging.getLogger(name=__name__)
12
12
 
@@ -19,7 +19,7 @@ class ReturnDuplicatorHigh(OptimizationPass, ReturnDuplicatorBase):
19
19
 
20
20
  ARCHES = None
21
21
  PLATFORMS = None
22
- STAGE = OptimizationPassStage.AFTER_VARIABLE_RECOVERY
22
+ STAGE = OptimizationPassStage.AFTER_GLOBAL_SIMPLIFICATION
23
23
  NAME = "Duplicate return-only blocks (high)"
24
24
  DESCRIPTION = __doc__
25
25
  STRUCTURING = [SAILRStructurer.NAME, DreamStructurer.NAME]
@@ -28,27 +28,22 @@ class ReturnDuplicatorHigh(OptimizationPass, ReturnDuplicatorBase):
28
28
  self,
29
29
  func,
30
30
  # settings
31
+ *,
32
+ vvar_id_start: int,
31
33
  max_calls_in_regions: int = 2,
32
34
  minimize_copies_for_regions: bool = True,
33
- region_identifier=None,
34
- vvar_id_start: int | None = None,
35
35
  scratch: dict[str, Any] | None = None,
36
36
  **kwargs,
37
37
  ):
38
- OptimizationPass.__init__(
39
- self, func, vvar_id_start=vvar_id_start, scratch=scratch, region_identifier=region_identifier, **kwargs
40
- )
38
+ OptimizationPass.__init__(self, func, vvar_id_start=vvar_id_start, scratch=scratch, **kwargs)
41
39
  ReturnDuplicatorBase.__init__(
42
40
  self,
43
41
  func,
44
42
  max_calls_in_regions=max_calls_in_regions,
45
43
  minimize_copies_for_regions=minimize_copies_for_regions,
46
- ri=region_identifier,
47
44
  vvar_id_start=vvar_id_start,
48
45
  scratch=scratch,
49
46
  )
50
- # since we run before the RegionIdentification pass in the decompiler, we need to collect it early here
51
- self._ri = self._recover_regions(self._graph)
52
47
 
53
48
  self.analyze()
54
49
 
@@ -60,6 +55,8 @@ class ReturnDuplicatorHigh(OptimizationPass, ReturnDuplicatorBase):
60
55
  return dst_is_const_ret
61
56
 
62
57
  def _analyze(self, cache=None):
58
+ # since we run before the RegionIdentification pass in the decompiler, we need to collect it early here
59
+ self._ri = self._recover_regions(self._graph)
63
60
  copy_graph = networkx.DiGraph(self._graph)
64
61
  if self._analyze_core(copy_graph):
65
62
  self.out_graph = self._simplify_graph(copy_graph)
@@ -150,7 +150,12 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
150
150
  if isinstance(expr.operands[1], Const) and expr.operands[1].value == 1:
151
151
  # x * 1 => x
152
152
  return expr.operands[0]
153
- if isinstance(expr.operands[0], Const) and isinstance(expr.operands[1], Const):
153
+ if (
154
+ isinstance(expr.operands[0], Const)
155
+ and expr.operands[0].is_int
156
+ and isinstance(expr.operands[1], Const)
157
+ and expr.operands[1].is_int
158
+ ):
154
159
  # constant multiplication
155
160
  mask = (1 << expr.bits) - 1
156
161
  return Const(
@@ -236,6 +241,10 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
236
241
  return expr.operands[1]
237
242
  if isinstance(expr.operands[1], Const) and expr.operands[1].value == 0:
238
243
  return expr.operands[0]
244
+ if isinstance(expr.operands[0], Const) and expr.operands[0].value == (1 << expr.operands[0].bits) - 1:
245
+ return expr.operands[0]
246
+ if isinstance(expr.operands[1], Const) and expr.operands[1].value == (1 << expr.operands[1].bits) - 1:
247
+ return expr.operands[1]
239
248
  if expr.operands[0].likes(expr.operands[1]):
240
249
  return expr.operands[0]
241
250
 
@@ -290,6 +299,7 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
290
299
  def _optimize_convert(expr: Convert):
291
300
  if (
292
301
  isinstance(expr.operand, Const)
302
+ and expr.operand.is_int
293
303
  and expr.from_type == Convert.TYPE_INT
294
304
  and expr.to_type == Convert.TYPE_INT
295
305
  and expr.from_bits > expr.to_bits
@@ -300,6 +310,7 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
300
310
  return Const(expr.idx, expr.operand.variable, v, expr.to_bits, **expr.operand.tags)
301
311
  if (
302
312
  isinstance(expr.operand, Const)
313
+ and expr.operand.is_int
303
314
  and expr.from_type == Convert.TYPE_INT
304
315
  and expr.to_type == Convert.TYPE_INT
305
316
  and expr.from_bits <= expr.to_bits
@@ -169,29 +169,65 @@ class RemoveRedundantConversions(PeepholeOptimizationExprBase):
169
169
  @staticmethod
170
170
  def _optimize_Convert(expr: Convert):
171
171
  operand_expr = expr.operand
172
- if isinstance(operand_expr, BinaryOp) and operand_expr.op in {
173
- "Mul",
174
- "Shl",
175
- "Div",
176
- "DivMod",
177
- "Mod",
178
- "Add",
179
- "Sub",
180
- }:
181
- op0, op1 = operand_expr.operands
182
- if (
183
- isinstance(op0, Convert)
184
- and isinstance(op1, Convert)
185
- and op0.from_bits == op1.from_bits
186
- and op0.to_bits == op1.to_bits
187
- and expr.from_bits == op0.to_bits
188
- and expr.to_bits == op1.from_bits
189
- ):
190
- return BinaryOp(
191
- operand_expr.idx,
192
- operand_expr.op,
193
- [op0.operand, op1.operand],
194
- expr.is_signed,
195
- **operand_expr.tags,
196
- )
172
+ if isinstance(operand_expr, BinaryOp):
173
+ if operand_expr.op in {
174
+ "Mul",
175
+ "Shl",
176
+ "Div",
177
+ "DivMod",
178
+ "Mod",
179
+ "Add",
180
+ "Sub",
181
+ }:
182
+ op0, op1 = operand_expr.operands
183
+ if (
184
+ isinstance(op0, Convert)
185
+ and isinstance(op1, Convert)
186
+ and op0.from_bits == op1.from_bits
187
+ and op0.to_bits == op1.to_bits
188
+ and expr.from_bits == op0.to_bits
189
+ and expr.to_bits == op1.from_bits
190
+ ):
191
+ return BinaryOp(
192
+ operand_expr.idx,
193
+ operand_expr.op,
194
+ [op0.operand, op1.operand],
195
+ expr.is_signed,
196
+ **operand_expr.tags,
197
+ )
198
+ elif operand_expr.op == "Or" and expr.from_bits > expr.to_bits:
199
+ # Conv(64->32,((vvar_183{reg 128} & 0xffffffff00000000<64>)
200
+ # | Conv(32->64, Load(addr=0x200002dc<32>, size=4, endness=Iend_LE))))
201
+ # =>
202
+ # Conv(64->32, Load(addr=0x200002dc<32>, size=4, endness=Iend_LE))
203
+ high_mask = ((1 << expr.from_bits) - 1) - ((1 << expr.to_bits) - 1)
204
+ op0, op1 = operand_expr.operands
205
+ if (
206
+ isinstance(op0, BinaryOp)
207
+ and op0.op == "And"
208
+ and isinstance(op0.operands[1], Const)
209
+ and op0.operands[1].value == high_mask
210
+ ):
211
+ return Convert(
212
+ expr.idx,
213
+ expr.from_bits,
214
+ expr.to_bits,
215
+ expr.is_signed,
216
+ op1,
217
+ **expr.tags,
218
+ )
219
+ if (
220
+ isinstance(op1, BinaryOp)
221
+ and op1.op == "And"
222
+ and isinstance(op1.operands[1], Const)
223
+ and op1.operands[1].value == high_mask
224
+ ):
225
+ return Convert(
226
+ expr.idx,
227
+ expr.from_bits,
228
+ expr.to_bits,
229
+ expr.is_signed,
230
+ op0,
231
+ **expr.tags,
232
+ )
197
233
  return None
@@ -1,4 +1,4 @@
1
- # pylint:disable=no-self-use,missing-class-docstring
1
+ # pylint:disable=no-self-use,too-many-boolean-expressions
2
2
  from __future__ import annotations
3
3
  from ailment.expression import BinaryOp, Const, Convert
4
4
 
@@ -7,6 +7,10 @@ from .utils import get_expr_shift_left_amount
7
7
 
8
8
 
9
9
  class RemoveRedundantShifts(PeepholeOptimizationExprBase):
10
+ """
11
+ Remove redundant bitshift operations.
12
+ """
13
+
10
14
  __slots__ = ()
11
15
 
12
16
  NAME = "Remove redundant bitshifts"
@@ -43,4 +47,49 @@ class RemoveRedundantShifts(PeepholeOptimizationExprBase):
43
47
  if expr.op in {"Shl", "Shr", "Sar"} and isinstance(expr.operands[1], Const) and expr.operands[1].value == 0:
44
48
  return expr.operands[0]
45
49
 
50
+ mask_hi32bits = 0xFFFFFFFF_00000000
51
+ exp_32bits = 0x1_00000000
52
+ if (
53
+ expr.op == "Shr"
54
+ and isinstance(expr.operands[1], Const)
55
+ and expr.operands[1].value == 32
56
+ and isinstance(expr.operands[0], BinaryOp)
57
+ and expr.operands[0].op == "Or"
58
+ ):
59
+ op0, op1 = expr.operands[0].operands
60
+ if (
61
+ isinstance(op1, Convert)
62
+ and op1.from_bits == 32
63
+ and op1.to_bits == 64
64
+ and op1.from_type == Convert.TYPE_INT
65
+ and op1.to_type == Convert.TYPE_INT
66
+ and isinstance(op0, BinaryOp)
67
+ and op0.op == "And"
68
+ ):
69
+ # (expr<64-bits> & 0xffffffff_00000000) | Conv(32->64, expr<32-bits>)) >> 32 ==> expr<64-bits> >> 32
70
+ inner_op0, inner_op1 = op0.operands
71
+ if isinstance(inner_op1, Const) and inner_op1.value == mask_hi32bits:
72
+ if (
73
+ isinstance(inner_op0, BinaryOp)
74
+ and isinstance(inner_op0.operands[1], Const)
75
+ and inner_op0.operands[1].value == exp_32bits
76
+ ):
77
+ return inner_op0.operands[0]
78
+ return BinaryOp(expr.idx, "Shr", [inner_op0, expr.operands[1]], expr.signed, **expr.tags)
79
+ return BinaryOp(expr.idx, "Shr", [op0, expr.operands[1]], expr.signed, **expr.tags)
80
+
81
+ for op0, op1 in [expr.operands[0].operands, expr.operands[0].operands[::-1]]:
82
+ # ((v11 & 0xffff_ffff | 10.0 * 0x1_00000000) >> 32) ==> 10.0
83
+ if (
84
+ isinstance(op0, BinaryOp)
85
+ and op0.op == "And"
86
+ and isinstance(op0.operands[1], Const)
87
+ and op0.operands[1].value == 0xFFFF_FFFF
88
+ and isinstance(op1, BinaryOp)
89
+ and op1.op == "Mul"
90
+ and isinstance(op1.operands[1], Const)
91
+ and op1.operands[1].value == 0x1_0000_0000
92
+ ):
93
+ return op1.operands[0]
94
+
46
95
  return None
@@ -21,6 +21,7 @@ from angr.analyses.decompiler.optimization_passes import (
21
21
  CallStatementRewriter,
22
22
  DeadblockRemover,
23
23
  SwitchReusedEntryRewriter,
24
+ ConditionConstantPropagation,
24
25
  )
25
26
 
26
27
 
@@ -47,6 +48,7 @@ preset_fast = DecompilationPreset(
47
48
  FlipBooleanCmp,
48
49
  InlinedStringTransformationSimplifier,
49
50
  CallStatementRewriter,
51
+ ConditionConstantPropagation,
50
52
  ],
51
53
  )
52
54
 
@@ -26,6 +26,7 @@ from angr.analyses.decompiler.optimization_passes import (
26
26
  InlinedStringTransformationSimplifier,
27
27
  CallStatementRewriter,
28
28
  SwitchReusedEntryRewriter,
29
+ ConditionConstantPropagation,
29
30
  )
30
31
 
31
32
 
@@ -57,6 +58,7 @@ preset_full = DecompilationPreset(
57
58
  InlinedStringTransformationSimplifier,
58
59
  CallStatementRewriter,
59
60
  SwitchReusedEntryRewriter,
61
+ ConditionConstantPropagation,
60
62
  ],
61
63
  )
62
64
 
@@ -88,6 +88,10 @@ class RegionSimplifier(Analysis):
88
88
  #
89
89
 
90
90
  def _fold_oneuse_expressions(self, region):
91
+ # Disabled until https://github.com/angr/angr/issues/5110 and related folding issues fixed
92
+ return region
93
+
94
+ # pylint:disable=unreachable
91
95
  variable_manager = self.variable_kb.variables[self.func.addr]
92
96
  expr_counter = ExpressionCounter(region, variable_manager)
93
97
 
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import logging
4
4
 
5
5
  from ailment.manager import Manager
6
- from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump, DirtyStatement
6
+ from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump, DirtyStatement, Jump
7
7
  from ailment.expression import (
8
8
  Expression,
9
9
  Register,
@@ -19,6 +19,7 @@ from ailment.expression import (
19
19
  ITE,
20
20
  Tmp,
21
21
  DirtyExpression,
22
+ Reinterpret,
22
23
  )
23
24
 
24
25
  from angr.engines.light.engine import SimEngineNostmtAIL
@@ -183,6 +184,12 @@ class SimEngineSSARewriting(
183
184
 
184
185
  return None
185
186
 
187
+ def _handle_stmt_Jump(self, stmt: Jump) -> Jump | None:
188
+ new_target = self._expr(stmt.target)
189
+ if new_target is not None:
190
+ return Jump(stmt.idx, new_target, stmt.target_idx, **stmt.tags)
191
+ return None
192
+
186
193
  def _handle_stmt_ConditionalJump(self, stmt: ConditionalJump) -> ConditionalJump | None:
187
194
  new_cond = self._expr(stmt.condition)
188
195
  new_true_target = self._expr(stmt.true_target) if stmt.true_target is not None else None
@@ -429,7 +436,18 @@ class SimEngineSSARewriting(
429
436
  def _handle_expr_Phi(self, expr):
430
437
  return None
431
438
 
432
- def _handle_expr_Reinterpret(self, expr):
439
+ def _handle_expr_Reinterpret(self, expr: Reinterpret) -> Reinterpret | None:
440
+ new_operand = self._expr(expr.operand)
441
+ if new_operand is not None:
442
+ return Reinterpret(
443
+ expr.idx,
444
+ expr.from_bits,
445
+ expr.from_type,
446
+ expr.to_bits,
447
+ expr.to_type,
448
+ new_operand,
449
+ **expr.tags,
450
+ )
433
451
  return None
434
452
 
435
453
  def _handle_expr_StackBaseOffset(self, expr):
@@ -205,7 +205,7 @@ class SimEngineSSATraversal(SimEngineLightAIL[TraversalState, None, None, None])
205
205
  _handle_binop_Set = _handle_binop_Default
206
206
 
207
207
  def _handle_unop_Default(self, expr):
208
- self._expr(expr.operands[0])
208
+ self._expr(expr.operand)
209
209
 
210
210
  _handle_unop_BitwiseNeg = _handle_unop_Default
211
211
  _handle_unop_Dereference = _handle_unop_Default
@@ -243,16 +243,17 @@ class SimEngineSSATraversal(SimEngineLightAIL[TraversalState, None, None, None])
243
243
  if expr.maddr is not None:
244
244
  self._expr(expr.maddr)
245
245
 
246
+ _handle_expr_Convert = _handle_unop_Default
247
+ _handle_expr_Reinterpret = _handle_unop_Default
248
+
246
249
  def _handle_Dummy(self, expr):
247
250
  pass
248
251
 
249
252
  _handle_expr_VirtualVariable = _handle_Dummy
250
253
  _handle_expr_Phi = _handle_Dummy
251
254
  _handle_expr_Load = _handle_Dummy
252
- _handle_expr_Convert = _handle_Dummy
253
255
  _handle_expr_Const = _handle_Dummy
254
256
  _handle_expr_MultiStatementExpression = _handle_Dummy
255
- _handle_expr_Reinterpret = _handle_Dummy
256
257
  _handle_expr_StackBaseOffset = _handle_Dummy
257
258
  _handle_expr_BasePointerOffset = _handle_Dummy
258
259
  _handle_expr_Call = _handle_Dummy
@@ -2504,6 +2504,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2504
2504
  omit_func_header=False,
2505
2505
  display_block_addrs=False,
2506
2506
  display_vvar_ids=False,
2507
+ min_data_addr: int = 0x400_000,
2507
2508
  ):
2508
2509
  super().__init__(flavor=flavor)
2509
2510
 
@@ -2578,6 +2579,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2578
2579
  self.omit_func_header = omit_func_header
2579
2580
  self.display_block_addrs = display_block_addrs
2580
2581
  self.display_vvar_ids = display_vvar_ids
2582
+ self.min_data_addr = min_data_addr
2581
2583
  self.text = None
2582
2584
  self.map_pos_to_node = None
2583
2585
  self.map_pos_to_addr = None
@@ -3519,8 +3521,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3519
3521
  expr.value
3520
3522
  ]
3521
3523
  inline_string = True
3522
- elif isinstance(type_, SimTypePointer) and isinstance(type_.pts_to, SimTypeChar):
3523
- # char*
3524
+ elif isinstance(type_, SimTypePointer) and isinstance(type_.pts_to, (SimTypeChar, SimTypeBottom)):
3525
+ # char* or void*
3524
3526
  # Try to get a string
3525
3527
  if (
3526
3528
  self._cfg is not None
@@ -3583,11 +3585,16 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3583
3585
  elif function_pointer:
3584
3586
  self._function_pointers.add(expr.reference_variable)
3585
3587
 
3588
+ var_access = None
3586
3589
  if variable is not None and not reference_values:
3587
3590
  cvar = self._variable(variable, None)
3588
3591
  offset = getattr(expr, "reference_variable_offset", 0)
3589
- return self._access_constant_offset_reference(self._get_variable_reference(cvar), offset, None)
3592
+ var_access = self._access_constant_offset_reference(self._get_variable_reference(cvar), offset, None)
3590
3593
 
3594
+ if var_access is not None and expr.value >= self.min_data_addr:
3595
+ return var_access
3596
+
3597
+ reference_values["offset"] = var_access
3591
3598
  return CConstant(expr.value, type_, reference_values=reference_values, tags=expr.tags, codegen=self)
3592
3599
 
3593
3600
  def _handle_Expr_UnaryOp(self, expr, **kwargs):
@@ -567,8 +567,13 @@ class DreamStructurer(StructurerBase):
567
567
  seq, cmp_lb, jump_table.jumptable_entries, i, node_b_addr, addr2nodes
568
568
  )
569
569
  # if we don't know what the end address of this switch-case structure is, let's figure it out
570
- switch_end_addr = node_b_addr if node_default is None else None
571
- self._switch_handle_gotos(cases, node_default, switch_end_addr)
570
+ switch_end_addr = (
571
+ node_b_addr
572
+ if node_default is None
573
+ else self._switch_find_switch_end_addr(cases, node_default, {nn.addr for nn in self._region.graph})
574
+ )
575
+ if switch_end_addr is not None:
576
+ self._switch_handle_gotos(cases, node_default, switch_end_addr)
572
577
 
573
578
  self._make_switch_cases_core(
574
579
  seq,