angr 9.2.158__cp310-abi3-macosx_11_0_arm64.whl → 9.2.160__cp310-abi3-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.
- angr/__init__.py +1 -1
- angr/ailment/__init__.py +81 -0
- angr/ailment/block.py +81 -0
- angr/ailment/block_walker.py +845 -0
- angr/ailment/constant.py +3 -0
- angr/ailment/converter_common.py +11 -0
- angr/ailment/converter_pcode.py +623 -0
- angr/ailment/converter_vex.py +798 -0
- angr/ailment/expression.py +1639 -0
- angr/ailment/manager.py +33 -0
- angr/ailment/statement.py +978 -0
- angr/ailment/tagged_object.py +61 -0
- angr/ailment/utils.py +114 -0
- angr/analyses/calling_convention/calling_convention.py +6 -2
- angr/analyses/decompiler/ail_simplifier.py +5 -5
- angr/analyses/decompiler/block_io_finder.py +4 -4
- angr/analyses/decompiler/block_similarity.py +2 -2
- angr/analyses/decompiler/block_simplifier.py +4 -4
- angr/analyses/decompiler/callsite_maker.py +2 -2
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +1 -1
- angr/analyses/decompiler/clinic.py +5 -2
- angr/analyses/decompiler/condition_processor.py +1 -1
- angr/analyses/decompiler/counters/boolean_counter.py +4 -4
- angr/analyses/decompiler/counters/call_counter.py +4 -4
- angr/analyses/decompiler/counters/expression_counters.py +5 -5
- angr/analyses/decompiler/counters/seq_cf_structure_counter.py +1 -1
- angr/analyses/decompiler/decompiler.py +17 -12
- angr/analyses/decompiler/dephication/dephication_base.py +12 -1
- angr/analyses/decompiler/dephication/graph_dephication.py +12 -5
- angr/analyses/decompiler/dephication/graph_rewriting.py +6 -10
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +109 -72
- angr/analyses/decompiler/dephication/rewriting_engine.py +32 -9
- angr/analyses/decompiler/dephication/seqnode_dephication.py +32 -10
- angr/analyses/decompiler/empty_node_remover.py +2 -2
- angr/analyses/decompiler/expression_narrower.py +6 -6
- angr/analyses/decompiler/goto_manager.py +2 -2
- angr/analyses/decompiler/jump_target_collector.py +1 -1
- angr/analyses/decompiler/label_collector.py +1 -1
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +25 -25
- angr/analyses/decompiler/optimization_passes/call_stmt_rewriter.py +1 -1
- angr/analyses/decompiler/optimization_passes/code_motion.py +2 -2
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +3 -3
- angr/analyses/decompiler/optimization_passes/const_derefs.py +3 -3
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +4 -4
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +2 -2
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +3 -3
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +4 -4
- angr/analyses/decompiler/optimization_passes/duplication_reverter/similarity.py +1 -1
- angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +4 -4
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +3 -3
- angr/analyses/decompiler/optimization_passes/engine_base.py +1 -1
- angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +3 -3
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +2 -2
- angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +3 -3
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +4 -4
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +25 -1
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +2 -2
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +4 -4
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +2 -2
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +3 -3
- angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py +3 -3
- angr/analyses/decompiler/optimization_passes/tag_slicer.py +1 -1
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_div.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_div_const_mul_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_shr_const_shr_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_sub_n.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/arm_cmpf.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/base.py +3 -3
- angr/analyses/decompiler/peephole_optimizations/basepointeroffset_add_n.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/bitwise_or_to_logical_or.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/bswap.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/coalesce_adjacent_shrs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/one_sub_bool.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/remove_empty_if_body.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_comparisons.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +3 -3
- angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rol_ror.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/utils.py +1 -1
- angr/analyses/decompiler/redundant_label_remover.py +1 -1
- angr/analyses/decompiler/region_identifier.py +4 -4
- angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -1
- angr/analyses/decompiler/region_simplifiers/cascading_ifs.py +1 -1
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +37 -8
- angr/analyses/decompiler/region_simplifiers/goto.py +1 -1
- angr/analyses/decompiler/region_simplifiers/if_.py +1 -1
- angr/analyses/decompiler/region_simplifiers/loop.py +1 -1
- angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -1
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +14 -2
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +3 -3
- angr/analyses/decompiler/region_simplifiers/switch_expr_simplifier.py +1 -1
- angr/analyses/decompiler/return_maker.py +1 -1
- angr/analyses/decompiler/seq_to_blocks.py +1 -1
- angr/analyses/decompiler/sequence_walker.py +2 -2
- angr/analyses/decompiler/ssailification/rewriting.py +4 -4
- angr/analyses/decompiler/ssailification/rewriting_engine.py +4 -4
- angr/analyses/decompiler/ssailification/rewriting_state.py +3 -3
- angr/analyses/decompiler/ssailification/ssailification.py +2 -2
- angr/analyses/decompiler/ssailification/traversal.py +1 -1
- angr/analyses/decompiler/ssailification/traversal_engine.py +11 -2
- angr/analyses/decompiler/structured_codegen/c.py +3 -3
- angr/analyses/decompiler/structuring/dream.py +1 -1
- angr/analyses/decompiler/structuring/phoenix.py +3 -3
- angr/analyses/decompiler/structuring/structurer_base.py +1 -1
- angr/analyses/decompiler/structuring/structurer_nodes.py +1 -2
- angr/analyses/decompiler/utils.py +1 -1
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
- angr/analyses/deobfuscator/string_obf_opt_passes.py +3 -3
- angr/analyses/deobfuscator/string_obf_peephole_optimizer.py +2 -2
- angr/analyses/propagator/propagator.py +1 -1
- angr/analyses/proximity_graph.py +2 -2
- angr/analyses/reaching_definitions/engine_ail.py +1 -1
- angr/analyses/reaching_definitions/reaching_definitions.py +1 -1
- angr/analyses/reaching_definitions/subject.py +1 -1
- angr/analyses/s_liveness.py +2 -2
- angr/analyses/s_propagator.py +3 -3
- angr/analyses/s_reaching_definitions/s_rda_model.py +1 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +3 -3
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -3
- angr/analyses/typehoon/simple_solver.py +231 -29
- angr/analyses/typehoon/typehoon.py +10 -2
- angr/analyses/variable_recovery/engine_ail.py +10 -22
- angr/analyses/variable_recovery/engine_base.py +1 -1
- angr/analyses/variable_recovery/variable_recovery_base.py +1 -1
- angr/analyses/variable_recovery/variable_recovery_fast.py +2 -2
- angr/engines/light/data.py +1 -1
- angr/engines/light/engine.py +1 -1
- angr/knowledge_plugins/key_definitions/atoms.py +1 -1
- angr/knowledge_plugins/propagations/prop_value.py +1 -1
- angr/knowledge_plugins/propagations/propagation_model.py +1 -1
- angr/knowledge_plugins/propagations/states.py +1 -1
- angr/knowledge_plugins/variables/variable_manager.py +1 -1
- angr/rustylib.abi3.so +0 -0
- angr/state_plugins/unicorn_engine.py +4 -4
- angr/{lib/angr_native.dylib → unicornlib.dylib} +0 -0
- angr/utils/ail.py +4 -4
- angr/utils/endness.py +1 -1
- angr/utils/ssa/__init__.py +14 -4
- angr/utils/ssa/tmp_uses_collector.py +4 -4
- angr/utils/ssa/vvar_uses_collector.py +4 -4
- {angr-9.2.158.dist-info → angr-9.2.160.dist-info}/METADATA +6 -7
- {angr-9.2.158.dist-info → angr-9.2.160.dist-info}/RECORD +195 -183
- {angr-9.2.158.dist-info → angr-9.2.160.dist-info}/WHEEL +0 -0
- {angr-9.2.158.dist-info → angr-9.2.160.dist-info}/entry_points.txt +0 -0
- {angr-9.2.158.dist-info → angr-9.2.160.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.158.dist-info → angr-9.2.160.dist-info}/top_level.txt +0 -0
|
@@ -9,9 +9,9 @@ import logging
|
|
|
9
9
|
import networkx
|
|
10
10
|
|
|
11
11
|
import claripy
|
|
12
|
-
from ailment.block import Block
|
|
13
|
-
from ailment.statement import Statement, ConditionalJump, Jump, Label, Return
|
|
14
|
-
from ailment.expression import Const, UnaryOp, MultiStatementExpression
|
|
12
|
+
from angr.ailment.block import Block
|
|
13
|
+
from angr.ailment.statement import Statement, ConditionalJump, Jump, Label, Return
|
|
14
|
+
from angr.ailment.expression import Const, UnaryOp, MultiStatementExpression
|
|
15
15
|
|
|
16
16
|
from angr.utils.graph import GraphUtils
|
|
17
17
|
from angr.utils.ail import is_phi_assignment, is_head_controlled_loop_block
|
|
@@ -3,9 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
import archinfo
|
|
5
5
|
|
|
6
|
-
from ailment import Block
|
|
7
|
-
from ailment.statement import Statement, Call, Assignment
|
|
8
|
-
from ailment.expression import Const, Register, VirtualVariable
|
|
6
|
+
from angr.ailment import Block
|
|
7
|
+
from angr.ailment.statement import Statement, Call, Assignment
|
|
8
|
+
from angr.ailment.expression import Const, Register, VirtualVariable
|
|
9
9
|
|
|
10
10
|
from angr.analyses.decompiler.optimization_passes.optimization_pass import OptimizationPass, OptimizationPassStage
|
|
11
11
|
from angr.analyses.decompiler.optimization_passes import register_optimization_pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from ailment.statement import Call
|
|
3
|
-
from ailment.expression import Const
|
|
2
|
+
from angr.ailment.statement import Call
|
|
3
|
+
from angr.ailment.expression import Const
|
|
4
4
|
import claripy
|
|
5
5
|
|
|
6
6
|
from angr.analyses.decompiler.peephole_optimizations.base import PeepholeOptimizationExprBase
|
angr/analyses/proximity_graph.py
CHANGED
angr/analyses/s_liveness.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import networkx
|
|
4
|
-
from ailment.expression import VirtualVariable
|
|
5
|
-
from ailment.statement import Assignment, Call, ConditionalJump
|
|
4
|
+
from angr.ailment.expression import VirtualVariable
|
|
5
|
+
from angr.ailment.statement import Assignment, Call, ConditionalJump
|
|
6
6
|
|
|
7
7
|
from angr.analyses import Analysis, register_analysis
|
|
8
8
|
from angr.utils.ail import is_head_controlled_loop_block, is_phi_assignment
|
angr/analyses/s_propagator.py
CHANGED
|
@@ -6,8 +6,8 @@ from collections import defaultdict
|
|
|
6
6
|
|
|
7
7
|
import networkx
|
|
8
8
|
|
|
9
|
-
from ailment.block import Block
|
|
10
|
-
from ailment.expression import (
|
|
9
|
+
from angr.ailment.block import Block
|
|
10
|
+
from angr.ailment.expression import (
|
|
11
11
|
Const,
|
|
12
12
|
VirtualVariable,
|
|
13
13
|
VirtualVariableCategory,
|
|
@@ -16,7 +16,7 @@ from ailment.expression import (
|
|
|
16
16
|
Convert,
|
|
17
17
|
Expression,
|
|
18
18
|
)
|
|
19
|
-
from ailment.statement import Assignment, Store, Return, Jump, ConditionalJump
|
|
19
|
+
from angr.ailment.statement import Assignment, Store, Return, Jump, ConditionalJump
|
|
20
20
|
|
|
21
21
|
from angr.knowledge_plugins.functions import Function
|
|
22
22
|
from angr.code_location import CodeLocation, ExternalCodeLocation
|
|
@@ -4,7 +4,7 @@ from collections import defaultdict
|
|
|
4
4
|
from collections.abc import Generator
|
|
5
5
|
from typing import Any, Literal, overload
|
|
6
6
|
|
|
7
|
-
from ailment.expression import VirtualVariable, Tmp
|
|
7
|
+
from angr.ailment.expression import VirtualVariable, Tmp
|
|
8
8
|
|
|
9
9
|
from angr.knowledge_plugins.key_definitions import atoms, Definition
|
|
10
10
|
from angr.code_location import CodeLocation
|
|
@@ -4,9 +4,9 @@ import logging
|
|
|
4
4
|
from collections.abc import Callable
|
|
5
5
|
from collections import defaultdict
|
|
6
6
|
|
|
7
|
-
from ailment import Block
|
|
8
|
-
from ailment.statement import Statement, Assignment, Call, Label
|
|
9
|
-
from ailment.expression import VirtualVariable, VirtualVariableCategory, Expression
|
|
7
|
+
from angr.ailment import Block
|
|
8
|
+
from angr.ailment.statement import Statement, Assignment, Call, Label
|
|
9
|
+
from angr.ailment.expression import VirtualVariable, VirtualVariableCategory, Expression
|
|
10
10
|
|
|
11
11
|
from angr.utils.ail import is_phi_assignment
|
|
12
12
|
from angr.utils.graph import GraphUtils
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from ailment.block import Block
|
|
4
|
-
from ailment.statement import Assignment, Call, Return
|
|
5
|
-
from ailment.expression import VirtualVariable
|
|
3
|
+
from angr.ailment.block import Block
|
|
4
|
+
from angr.ailment.statement import Assignment, Call, Return
|
|
5
|
+
from angr.ailment.expression import VirtualVariable
|
|
6
6
|
import networkx
|
|
7
7
|
|
|
8
8
|
from angr.knowledge_plugins.functions import Function
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint:disable=missing-class-docstring
|
|
1
|
+
# pylint:disable=missing-class-docstring,too-many-boolean-expressions
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import enum
|
|
4
4
|
from collections import defaultdict
|
|
@@ -432,7 +432,14 @@ class SimpleSolver:
|
|
|
432
432
|
improvements.
|
|
433
433
|
"""
|
|
434
434
|
|
|
435
|
-
def __init__(
|
|
435
|
+
def __init__(
|
|
436
|
+
self,
|
|
437
|
+
bits: int,
|
|
438
|
+
constraints,
|
|
439
|
+
typevars,
|
|
440
|
+
constraint_set_degradation_threshold: int = 150,
|
|
441
|
+
stackvar_max_sizes: dict[TypeVariable, int] | None = None,
|
|
442
|
+
):
|
|
436
443
|
if bits not in (32, 64):
|
|
437
444
|
raise ValueError(f"Pointer size {bits} is not supported. Expect 32 or 64.")
|
|
438
445
|
|
|
@@ -440,6 +447,7 @@ class SimpleSolver:
|
|
|
440
447
|
self._constraints: dict[TypeVariable, set[TypeConstraint]] = constraints
|
|
441
448
|
self._typevars: set[TypeVariable] = typevars
|
|
442
449
|
self.stackvar_max_sizes = stackvar_max_sizes if stackvar_max_sizes is not None else {}
|
|
450
|
+
self._constraint_set_degradation_threshold = constraint_set_degradation_threshold
|
|
443
451
|
self._base_lattice = BASE_LATTICES[bits]
|
|
444
452
|
self._base_lattice_inverted = networkx.DiGraph()
|
|
445
453
|
for src, dst in self._base_lattice.edges:
|
|
@@ -459,7 +467,11 @@ class SimpleSolver:
|
|
|
459
467
|
self.processed_constraints_count += len(self._constraints[typevar])
|
|
460
468
|
|
|
461
469
|
self._constraints[typevar] |= self._eq_constraints_from_add(typevar)
|
|
462
|
-
self._constraints[typevar]
|
|
470
|
+
self._constraints[typevar] |= self._discover_equivalence(self._constraints[typevar])
|
|
471
|
+
new_constraints, replacements = self._handle_equivalence(self._constraints[typevar])
|
|
472
|
+
self._equivalence |= replacements
|
|
473
|
+
self._constraints[typevar] = new_constraints
|
|
474
|
+
self._constraints[typevar] = self._filter_constraints(self._constraints[typevar])
|
|
463
475
|
|
|
464
476
|
self.simplified_constraints_count += len(self._constraints[typevar])
|
|
465
477
|
|
|
@@ -517,11 +529,18 @@ class SimpleSolver:
|
|
|
517
529
|
|
|
518
530
|
_, sketches = self.infer_shapes(typevars, constraints)
|
|
519
531
|
constraintset2tvs = defaultdict(set)
|
|
532
|
+
tvs_seen = set()
|
|
520
533
|
for idx, tv in enumerate(constrained_typevars):
|
|
521
534
|
_l.debug("Collecting constraints for type variable %r (%d/%d)", tv, idx + 1, len(constrained_typevars))
|
|
535
|
+
if tv in tvs_seen:
|
|
536
|
+
continue
|
|
522
537
|
# build a sub constraint set for the type variable
|
|
523
|
-
constraint_subset =
|
|
524
|
-
|
|
538
|
+
constraint_subset, related_tvs = self._generate_constraint_subset(constraints, {tv})
|
|
539
|
+
# drop all type vars outside constrained_typevars
|
|
540
|
+
related_tvs = related_tvs.intersection(constrained_typevars)
|
|
541
|
+
tvs_seen |= related_tvs
|
|
542
|
+
frozen_constraint_subset = frozenset(constraint_subset)
|
|
543
|
+
constraintset2tvs[frozen_constraint_subset] = related_tvs
|
|
525
544
|
|
|
526
545
|
for idx, (constraint_subset, tvs) in enumerate(constraintset2tvs.items()):
|
|
527
546
|
_l.debug(
|
|
@@ -534,8 +553,31 @@ class SimpleSolver:
|
|
|
534
553
|
)
|
|
535
554
|
self.eqclass_constraints_count.append(len(constraint_subset))
|
|
536
555
|
|
|
537
|
-
|
|
538
|
-
|
|
556
|
+
if len(constraint_subset) > self._constraint_set_degradation_threshold:
|
|
557
|
+
_l.debug(
|
|
558
|
+
"Constraint subset contains %d constraints, which is over the limit of %d. Enter degradation.",
|
|
559
|
+
len(constraint_subset),
|
|
560
|
+
self._constraint_set_degradation_threshold,
|
|
561
|
+
)
|
|
562
|
+
constraint_subset = self._degrade_constraint_set(constraint_subset)
|
|
563
|
+
_l.debug("Degraded constraint subset to %d constraints.", len(constraint_subset))
|
|
564
|
+
|
|
565
|
+
while constraint_subset:
|
|
566
|
+
|
|
567
|
+
_l.debug("Working with %d constraints.", len(constraint_subset))
|
|
568
|
+
|
|
569
|
+
# remove constraints that are a <: b where a only appears once; in this case, the solution fo a is
|
|
570
|
+
# entirely determined by the solution of b (which is the upper bound of a)
|
|
571
|
+
filtered_constraint_subset, ub_subtypes = self._filter_leaf_typevars(constraint_subset, tvs)
|
|
572
|
+
_l.debug(
|
|
573
|
+
"Filtered %d leaf typevars; %d constraints remain.",
|
|
574
|
+
len(ub_subtypes),
|
|
575
|
+
len(filtered_constraint_subset),
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
base_constraint_graph = self._generate_constraint_graph(
|
|
579
|
+
filtered_constraint_subset, tvs | PRIMITIVE_TYPES
|
|
580
|
+
)
|
|
539
581
|
primitive_constraints = self._generate_primitive_constraints(tvs, base_constraint_graph)
|
|
540
582
|
tvs_with_primitive_constraints = set()
|
|
541
583
|
for primitive_constraint in primitive_constraints:
|
|
@@ -546,12 +588,22 @@ class SimpleSolver:
|
|
|
546
588
|
solutions = {}
|
|
547
589
|
self.determine(sketches, tvs_with_primitive_constraints, solutions)
|
|
548
590
|
_l.debug("Determined solutions for %d type variable(s).", len(tvs_with_primitive_constraints))
|
|
591
|
+
|
|
592
|
+
leaf_solutions = 0
|
|
593
|
+
for tv_, ub_tv in ub_subtypes.items():
|
|
594
|
+
if ub_tv in solutions:
|
|
595
|
+
solutions[tv_] = solutions[ub_tv]
|
|
596
|
+
leaf_solutions += 1
|
|
597
|
+
elif isinstance(ub_tv, TypeConstant):
|
|
598
|
+
solutions[tv_] = ub_tv
|
|
599
|
+
leaf_solutions += 1
|
|
600
|
+
_l.debug("Determined solutions for %d leaf type variable(s).", leaf_solutions)
|
|
601
|
+
|
|
549
602
|
if not solutions:
|
|
550
603
|
break
|
|
551
|
-
|
|
552
604
|
self.solution |= solutions
|
|
553
605
|
|
|
554
|
-
tvs = {tv for tv in tvs if tv not in
|
|
606
|
+
tvs = {tv for tv in tvs if tv not in solutions}
|
|
555
607
|
if not tvs:
|
|
556
608
|
break
|
|
557
609
|
# rewrite existing constraints
|
|
@@ -559,7 +611,7 @@ class SimpleSolver:
|
|
|
559
611
|
for constraint in constraint_subset:
|
|
560
612
|
rewritten = self._rewrite_constraint(constraint, solutions)
|
|
561
613
|
new_constraint_subset.add(rewritten)
|
|
562
|
-
constraint_subset = new_constraint_subset
|
|
614
|
+
constraint_subset = self._filter_constraints(new_constraint_subset)
|
|
563
615
|
|
|
564
616
|
# set the solution for missing type vars to TOP
|
|
565
617
|
self.determine(sketches, set(sketches).difference(set(self.solution)), self.solution)
|
|
@@ -775,14 +827,45 @@ class SimpleSolver:
|
|
|
775
827
|
new_constraints.add(Equivalence(constraint.type_1, constraint.type_r))
|
|
776
828
|
return new_constraints
|
|
777
829
|
|
|
778
|
-
|
|
830
|
+
@staticmethod
|
|
831
|
+
def _discover_equivalence(constraints: set[TypeConstraint]) -> set[Equivalence]:
|
|
832
|
+
"""
|
|
833
|
+
a <:b && b <: a ==> a == b
|
|
834
|
+
"""
|
|
835
|
+
|
|
836
|
+
new_eq_constraints: set[Equivalence] = set()
|
|
837
|
+
subtypes = defaultdict(set)
|
|
838
|
+
for constraint in constraints:
|
|
839
|
+
if isinstance(constraint, Subtype):
|
|
840
|
+
sub_type = constraint.sub_type
|
|
841
|
+
super_type = constraint.super_type
|
|
842
|
+
subtypes[sub_type].add(super_type)
|
|
843
|
+
|
|
844
|
+
# check everything
|
|
845
|
+
seen = set()
|
|
846
|
+
for tv, tv_supers in subtypes.items():
|
|
847
|
+
for tv_super in tv_supers:
|
|
848
|
+
if tv_super in subtypes and tv in subtypes[tv_super]: # noqa: SIM102
|
|
849
|
+
# we have a pair of subtypes that are equivalent
|
|
850
|
+
if (tv, tv_super) not in seen and (tv_super, tv) not in seen:
|
|
851
|
+
new_eq_constraints.add(Equivalence(tv, tv_super))
|
|
852
|
+
seen.add((tv, tv_super))
|
|
853
|
+
|
|
854
|
+
_l.debug(
|
|
855
|
+
"Discovered %d equivalence constraints from %d constraints.", len(new_eq_constraints), len(constraints)
|
|
856
|
+
)
|
|
857
|
+
return new_eq_constraints
|
|
858
|
+
|
|
859
|
+
@staticmethod
|
|
860
|
+
def _handle_equivalence(
|
|
861
|
+
constraint_set: set[TypeConstraint],
|
|
862
|
+
) -> tuple[set[TypeConstraint], dict[TypeVariable, TypeVariable | TypeConstant]]:
|
|
779
863
|
graph = networkx.Graph()
|
|
780
864
|
|
|
781
|
-
replacements = {}
|
|
782
|
-
constraints = set()
|
|
865
|
+
replacements: dict[TypeVariable, TypeVariable | TypeConstant] = {}
|
|
783
866
|
|
|
784
867
|
# collect equivalence relations
|
|
785
|
-
for constraint in
|
|
868
|
+
for constraint in constraint_set:
|
|
786
869
|
if isinstance(constraint, Equivalence):
|
|
787
870
|
# | type_a == type_b
|
|
788
871
|
# we apply unification and removes one of them
|
|
@@ -803,15 +886,30 @@ class SimpleSolver:
|
|
|
803
886
|
for tv in components_lst[1:]:
|
|
804
887
|
replacements[tv] = representative
|
|
805
888
|
|
|
806
|
-
|
|
807
|
-
|
|
889
|
+
constraints = SimpleSolver._rewrite_constraints_with_replacements(constraint_set, replacements)
|
|
890
|
+
|
|
891
|
+
# import pprint
|
|
892
|
+
# print("Replacements")
|
|
893
|
+
# pprint.pprint(replacements)
|
|
894
|
+
# print("Constraints (after replacement)")
|
|
895
|
+
# pprint.pprint(constraints)
|
|
896
|
+
|
|
897
|
+
return constraints, replacements
|
|
898
|
+
|
|
899
|
+
@staticmethod
|
|
900
|
+
def _rewrite_constraints_with_replacements(
|
|
901
|
+
constraints: set[TypeConstraint], replacements: dict[TypeVariable, TypeVariable]
|
|
902
|
+
) -> set[TypeConstraint]:
|
|
903
|
+
# replace constraints according to a dictionary of type variable replacements
|
|
904
|
+
replaced_constraints = set()
|
|
905
|
+
for constraint in constraints:
|
|
808
906
|
if isinstance(constraint, Existence):
|
|
809
907
|
replaced, new_constraint = constraint.replace(replacements)
|
|
810
908
|
|
|
811
909
|
if replaced:
|
|
812
|
-
|
|
910
|
+
replaced_constraints.add(new_constraint)
|
|
813
911
|
else:
|
|
814
|
-
|
|
912
|
+
replaced_constraints.add(constraint)
|
|
815
913
|
|
|
816
914
|
elif isinstance(constraint, Subtype):
|
|
817
915
|
# subtype <: supertype
|
|
@@ -819,18 +917,122 @@ class SimpleSolver:
|
|
|
819
917
|
replaced, new_constraint = constraint.replace(replacements)
|
|
820
918
|
|
|
821
919
|
if replaced:
|
|
822
|
-
|
|
920
|
+
replaced_constraints.add(new_constraint)
|
|
823
921
|
else:
|
|
824
|
-
|
|
922
|
+
replaced_constraints.add(constraint)
|
|
923
|
+
return replaced_constraints
|
|
825
924
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
925
|
+
@staticmethod
|
|
926
|
+
def _filter_constraints(constraints: set[TypeConstraint]) -> set[TypeConstraint]:
|
|
927
|
+
"""
|
|
928
|
+
Filter out constraints that we don't yet support.
|
|
929
|
+
"""
|
|
930
|
+
|
|
931
|
+
filtered_constraints = set()
|
|
932
|
+
for constraint in constraints:
|
|
933
|
+
dropped = False
|
|
934
|
+
if isinstance(constraint, Subtype) and (
|
|
935
|
+
(isinstance(constraint.sub_type, TypeConstant) and isinstance(constraint.super_type, TypeConstant))
|
|
936
|
+
or (
|
|
937
|
+
isinstance(constraint.sub_type, DerivedTypeVariable)
|
|
938
|
+
and isinstance(constraint.sub_type.labels[-1], ConvertTo)
|
|
939
|
+
)
|
|
940
|
+
or (
|
|
941
|
+
isinstance(constraint.sub_type, TypeVariable)
|
|
942
|
+
and isinstance(constraint.super_type, TypeVariable)
|
|
943
|
+
and constraint.sub_type == constraint.super_type
|
|
944
|
+
)
|
|
945
|
+
):
|
|
946
|
+
dropped = True
|
|
831
947
|
|
|
832
|
-
|
|
833
|
-
|
|
948
|
+
if not dropped:
|
|
949
|
+
filtered_constraints.add(constraint)
|
|
950
|
+
|
|
951
|
+
return filtered_constraints
|
|
952
|
+
|
|
953
|
+
@staticmethod
|
|
954
|
+
def _filter_leaf_typevars(
|
|
955
|
+
constraints: set[TypeConstraint], tvs_to_solve: set[TypeVariable]
|
|
956
|
+
) -> tuple[set[TypeConstraint], dict[TypeVariable, TypeVariable]]:
|
|
957
|
+
"""
|
|
958
|
+
Filter out leaf type variables that only appear once in the constraints. These type variables are not
|
|
959
|
+
interesting and can be removed from the constraints.
|
|
960
|
+
"""
|
|
961
|
+
|
|
962
|
+
sub_typevars = defaultdict(set)
|
|
963
|
+
tv_to_dtvs: dict[TypeVariable, set[TypeVariable | DerivedTypeVariable]] = defaultdict(set)
|
|
964
|
+
for constraint in constraints:
|
|
965
|
+
if isinstance(constraint, Subtype):
|
|
966
|
+
if isinstance(constraint.sub_type, TypeVariable):
|
|
967
|
+
sub_typevars[constraint.sub_type].add(constraint.super_type)
|
|
968
|
+
for tv in [constraint.sub_type, constraint.super_type]:
|
|
969
|
+
if isinstance(tv, DerivedTypeVariable):
|
|
970
|
+
tv_to_dtvs[tv.type_var].add(constraint.sub_type)
|
|
971
|
+
elif isinstance(tv, TypeVariable):
|
|
972
|
+
tv_to_dtvs[tv].add(constraint.sub_type)
|
|
973
|
+
|
|
974
|
+
ub_subtypes: dict[TypeVariable, TypeVariable] = {}
|
|
975
|
+
for tv, dtvs in tv_to_dtvs.items():
|
|
976
|
+
if len(dtvs) == 1 and tv in sub_typevars and len(sub_typevars[tv]) == 1:
|
|
977
|
+
ub = next(iter(sub_typevars[tv]))
|
|
978
|
+
if ub in tvs_to_solve:
|
|
979
|
+
ub_subtypes[tv] = ub
|
|
980
|
+
|
|
981
|
+
filtered_constraints = set()
|
|
982
|
+
for constraint in constraints:
|
|
983
|
+
if isinstance(constraint, Subtype) and constraint.sub_type in ub_subtypes:
|
|
984
|
+
continue
|
|
985
|
+
filtered_constraints.add(constraint)
|
|
986
|
+
|
|
987
|
+
return filtered_constraints, ub_subtypes
|
|
988
|
+
|
|
989
|
+
def _degrade_constraint_set(self, constraints: set[TypeConstraint]) -> set[TypeConstraint]:
|
|
990
|
+
"""
|
|
991
|
+
Degrade the constraint set to a smaller set of constraints to speed up the DFA generation process.
|
|
992
|
+
"""
|
|
993
|
+
|
|
994
|
+
tv_with_ls = defaultdict(set) # tv_with_ls are type variables with Loads or Stores
|
|
995
|
+
graph = networkx.Graph()
|
|
996
|
+
|
|
997
|
+
for constraint in constraints:
|
|
998
|
+
if isinstance(constraint, Subtype):
|
|
999
|
+
if isinstance(constraint.sub_type, DerivedTypeVariable) and isinstance(
|
|
1000
|
+
constraint.sub_type.labels[0], (Load, Store)
|
|
1001
|
+
):
|
|
1002
|
+
tv_with_ls[constraint.sub_type.type_var].add(constraint.sub_type)
|
|
1003
|
+
if type(constraint.sub_type) is TypeVariable and type(constraint.super_type) is TypeVariable:
|
|
1004
|
+
graph.add_edge(constraint.sub_type, constraint.super_type)
|
|
1005
|
+
|
|
1006
|
+
tv_to_degrade = set()
|
|
1007
|
+
for tv, dtvs in tv_with_ls.items():
|
|
1008
|
+
if len(dtvs) > 5:
|
|
1009
|
+
# degrade all subtype relationships involving this type variable to equivalence
|
|
1010
|
+
tv_to_degrade.add(tv)
|
|
1011
|
+
|
|
1012
|
+
replacements = {}
|
|
1013
|
+
for components in networkx.connected_components(graph):
|
|
1014
|
+
if len(components) == 1:
|
|
1015
|
+
continue
|
|
1016
|
+
if any(tv in tv_to_degrade for tv in components):
|
|
1017
|
+
components_lst = sorted(components, key=str)
|
|
1018
|
+
representative = components_lst[0]
|
|
1019
|
+
for tv in components_lst[1:]:
|
|
1020
|
+
replacements[tv] = representative
|
|
1021
|
+
|
|
1022
|
+
degraded_constraints = self._rewrite_constraints_with_replacements(constraints, replacements)
|
|
1023
|
+
|
|
1024
|
+
# discover more equivalence relations
|
|
1025
|
+
eq_constraints = self._discover_equivalence(degraded_constraints)
|
|
1026
|
+
_l.debug("Discovered %d equivalence constraints from degraded constraints.", len(eq_constraints))
|
|
1027
|
+
if eq_constraints:
|
|
1028
|
+
degraded_constraints, eq_replacements = self._handle_equivalence(degraded_constraints | eq_constraints)
|
|
1029
|
+
self._equivalence |= eq_replacements
|
|
1030
|
+
|
|
1031
|
+
# filter them
|
|
1032
|
+
degraded_constraints = self._filter_constraints(degraded_constraints)
|
|
1033
|
+
|
|
1034
|
+
self._equivalence |= replacements
|
|
1035
|
+
return degraded_constraints
|
|
834
1036
|
|
|
835
1037
|
def _convert_arrays(self, constraints):
|
|
836
1038
|
for constraint in constraints:
|
|
@@ -860,7 +1062,7 @@ class SimpleSolver:
|
|
|
860
1062
|
@staticmethod
|
|
861
1063
|
def _generate_constraint_subset(
|
|
862
1064
|
constraints: set[TypeConstraint], typevars: set[TypeVariable]
|
|
863
|
-
) -> set[TypeConstraint]:
|
|
1065
|
+
) -> tuple[set[TypeConstraint], set[TypeVariable]]:
|
|
864
1066
|
subset = set()
|
|
865
1067
|
related_typevars = set(typevars)
|
|
866
1068
|
while True:
|
|
@@ -890,7 +1092,7 @@ class SimpleSolver:
|
|
|
890
1092
|
if not new:
|
|
891
1093
|
break
|
|
892
1094
|
subset |= new
|
|
893
|
-
return subset
|
|
1095
|
+
return subset, related_typevars
|
|
894
1096
|
|
|
895
1097
|
def _generate_constraint_graph(
|
|
896
1098
|
self, constraints: set[TypeConstraint], interesting_variables: set[DerivedTypeVariable]
|
|
@@ -40,6 +40,7 @@ class Typehoon(Analysis):
|
|
|
40
40
|
must_struct: set[TypeVariable] | None = None,
|
|
41
41
|
stackvar_max_sizes: dict[TypeVariable, int] | None = None,
|
|
42
42
|
stack_offset_tvs: dict[int, TypeVariable] | None = None,
|
|
43
|
+
constraint_set_degradation_threshold: int = 150,
|
|
43
44
|
):
|
|
44
45
|
"""
|
|
45
46
|
|
|
@@ -57,6 +58,7 @@ class Typehoon(Analysis):
|
|
|
57
58
|
self._must_struct = must_struct
|
|
58
59
|
self._stackvar_max_sizes = stackvar_max_sizes if stackvar_max_sizes is not None else {}
|
|
59
60
|
self._stack_offset_tvs = stack_offset_tvs if stack_offset_tvs is not None else {}
|
|
61
|
+
self._constraint_set_degradation_threshold = constraint_set_degradation_threshold
|
|
60
62
|
|
|
61
63
|
self.bits = self.project.arch.bits
|
|
62
64
|
self.solution = None
|
|
@@ -193,7 +195,7 @@ class Typehoon(Analysis):
|
|
|
193
195
|
self.simtypes_solution.update(self._ground_truth)
|
|
194
196
|
|
|
195
197
|
@staticmethod
|
|
196
|
-
def _resolve_derived(tv):
|
|
198
|
+
def _resolve_derived(tv: TypeVariable | DerivedTypeVariable) -> TypeVariable:
|
|
197
199
|
return tv.type_var if isinstance(tv, DerivedTypeVariable) else tv
|
|
198
200
|
|
|
199
201
|
def _solve(self):
|
|
@@ -211,7 +213,13 @@ class Typehoon(Analysis):
|
|
|
211
213
|
if isinstance(constraint.super_type, TypeVariable):
|
|
212
214
|
typevars.add(self._resolve_derived(constraint.super_type))
|
|
213
215
|
|
|
214
|
-
solver = SimpleSolver(
|
|
216
|
+
solver = SimpleSolver(
|
|
217
|
+
self.bits,
|
|
218
|
+
self._constraints,
|
|
219
|
+
typevars,
|
|
220
|
+
stackvar_max_sizes=self._stackvar_max_sizes,
|
|
221
|
+
constraint_set_degradation_threshold=self._constraint_set_degradation_threshold,
|
|
222
|
+
)
|
|
215
223
|
self.solution = solver.solution
|
|
216
224
|
self.processed_constraints_count = solver.processed_constraints_count
|
|
217
225
|
self.eqclass_constraints_count = solver.eqclass_constraints_count
|