From 651c7859df1c7a913e21f4f63ca3aa62d73aced7 Mon Sep 17 00:00:00 2001 From: fennec Date: Sun, 12 Apr 2026 18:09:43 +0000 Subject: [PATCH] fix: filter is_constructor_variables in printers Skip synthetic constructor-variable functions in printers that iterate over contract.functions. These fake functions (slitherConstructorVariables, slitherConstructorConstantVariables) are internal bookkeeping and shouldn't appear in printer output. Fixes #865 --- slither/printers/call/call_graph.py | 14 ++++++++++++-- slither/printers/functions/authorization.py | 2 ++ slither/printers/functions/cfg.py | 2 ++ slither/printers/functions/dominator.py | 2 ++ slither/printers/summary/evm.py | 2 ++ slither/printers/summary/modifier_calls.py | 2 ++ slither/printers/summary/require_calls.py | 2 ++ slither/printers/summary/slithir.py | 2 ++ slither/printers/summary/slithir_ssa.py | 2 ++ 9 files changed, 28 insertions(+), 2 deletions(-) diff --git a/slither/printers/call/call_graph.py b/slither/printers/call/call_graph.py index 9e581177bf..79080df601 100644 --- a/slither/printers/call/call_graph.py +++ b/slither/printers/call/call_graph.py @@ -332,7 +332,9 @@ def output(self, filename: str) -> Output: ] all_functions = [item for sublist in all_functionss for item in sublist] all_functions_as_dict = { - function.canonical_name: function for function in all_functions + function.canonical_name: function + for function in all_functions + if not function.is_constructor_variables } content = "\n".join( ["strict digraph {"] @@ -352,7 +354,15 @@ def output(self, filename: str) -> Output: ["strict digraph {"] + ['rankdir="LR"'] + ["node [shape=box]"] - + [_process_functions(derived_contract.functions)] + + [ + _process_functions( + [ + f + for f in derived_contract.functions + if not f.is_constructor_variables + ] + ) + ] + ["}"] ) f.write(content) diff --git a/slither/printers/functions/authorization.py b/slither/printers/functions/authorization.py index 52fa73a22f..dfb6406b45 100644 --- a/slither/printers/functions/authorization.py +++ b/slither/printers/functions/authorization.py @@ -48,6 +48,8 @@ def output(self, _filename: str) -> Output: ["Function", "State variables written", "Conditions on msg.sender"] ) for function in contract.functions: + if function.is_constructor_variables: + continue state_variables_written = [ v.name for v in function.all_state_variables_written() if v.name ] diff --git a/slither/printers/functions/cfg.py b/slither/printers/functions/cfg.py index 9d9afb7044..47ac8bef48 100644 --- a/slither/printers/functions/cfg.py +++ b/slither/printers/functions/cfg.py @@ -19,6 +19,8 @@ def output(self, filename: str) -> Output: all_files = [] for contract in self.contracts: # type: ignore for function in contract.functions + list(contract.modifiers): + if function.is_constructor_variables: + continue if filename: new_filename = f"{filename}-{contract.name}-{function.full_name}.dot" else: diff --git a/slither/printers/functions/dominator.py b/slither/printers/functions/dominator.py index 069a1ab266..b5c82a4f60 100644 --- a/slither/printers/functions/dominator.py +++ b/slither/printers/functions/dominator.py @@ -19,6 +19,8 @@ def output(self, filename: str) -> Output: all_files = [] for contract in self.contracts: for function in contract.functions + contract.modifiers: + if function.is_constructor_variables: + continue if filename: new_filename = f"{filename}-{contract.name}-{function.full_name}.dot" else: diff --git a/slither/printers/summary/evm.py b/slither/printers/summary/evm.py index 551ba132dc..1f8dfd9a68 100644 --- a/slither/printers/summary/evm.py +++ b/slither/printers/summary/evm.py @@ -130,6 +130,8 @@ def output(self, _filename): continue for function in contract.functions: + if function.is_constructor_variables: + continue txt += blue(f"\tFunction {function.canonical_name}\n") txt += self.build_element_node_str( diff --git a/slither/printers/summary/modifier_calls.py b/slither/printers/summary/modifier_calls.py index 218cf6ea6c..bf49a6c274 100644 --- a/slither/printers/summary/modifier_calls.py +++ b/slither/printers/summary/modifier_calls.py @@ -27,6 +27,8 @@ def output(self, _filename): txt = f"\nContract {contract.name}" table = MyPrettyTable(["Function", "Modifiers"]) for function in contract.functions: + if function.is_constructor_variables: + continue modifiers = function.modifiers for ir in function.all_internal_calls(): if isinstance(ir.function, Function): diff --git a/slither/printers/summary/require_calls.py b/slither/printers/summary/require_calls.py index 12705a5452..ad0b0bd242 100644 --- a/slither/printers/summary/require_calls.py +++ b/slither/printers/summary/require_calls.py @@ -38,6 +38,8 @@ def output(self, _filename): txt = f"\nContract {contract.name}" table = MyPrettyTable(["Function", "require or assert"]) for function in contract.functions: + if function.is_constructor_variables: + continue require = function.all_slithir_operations() require = [ ir diff --git a/slither/printers/summary/slithir.py b/slither/printers/summary/slithir.py index 145bccea8f..987fc9c87a 100644 --- a/slither/printers/summary/slithir.py +++ b/slither/printers/summary/slithir.py @@ -39,6 +39,8 @@ def output(self, _filename): for contract in compilation_unit.contracts: txt += f"Contract {contract.name}\n" for function in contract.functions: + if function.is_constructor_variables: + continue txt += f"\tFunction {function.canonical_name} {'' if function.is_shadowed else '(*)'}\n" txt += _print_function(function) for modifier in contract.modifiers: diff --git a/slither/printers/summary/slithir_ssa.py b/slither/printers/summary/slithir_ssa.py index 535879f413..ec3a746e3b 100644 --- a/slither/printers/summary/slithir_ssa.py +++ b/slither/printers/summary/slithir_ssa.py @@ -22,6 +22,8 @@ def output(self, _filename): for contract in self.contracts: txt += f"Contract {contract.name}" + "\n" for function in contract.functions: + if function.is_constructor_variables: + continue txt += f"\tFunction {function.canonical_name}" + "\n" for node in function.nodes: if node.expression: