@@ -81,5 +81,38 @@ def test_normal_path_is_untouched_without_jit(self):
8181 self .assertIn (PROMPT , out )
8282
8383
84+ # Tool id 3 is unused by CPython's own well-known ids (DEBUGGER=0, COVERAGE=1, PROFILER=2, OPTIMIZER=5)
85+ _TEST_TOOL_ID = 3
86+
87+ _MONITORING_DRIVER = """
88+ import sys
89+ sys.path.insert(0, %r)
90+ sys.monitoring.use_tool_id(%d, "test-tool")
91+ sys.monitoring.set_events(%d, sys.monitoring.events.PY_START)
92+ import sqlmap
93+ print(sys.monitoring.get_tool(%d))
94+ print(sys.monitoring.get_events(%d))
95+ """ % (ROOT , _TEST_TOOL_ID , _TEST_TOOL_ID , _TEST_TOOL_ID , _TEST_TOOL_ID )
96+
97+
98+ class TestMonitoringGuard (unittest .TestCase ):
99+ """
100+ The other half of the cpython#156319 mitigation: the tier-2 corruption needs BOTH the JIT and
101+ an active sys.monitoring tool (debugger/profiler/coverage) at once. sqlmap has no legitimate
102+ reason to run a scan with one attached, so it silences any already-registered tool's events as
103+ the very first thing at import time (Reference: 'https://github.com/python/cpython/issues/156319').
104+ """
105+
106+ def test_active_tool_is_silenced_but_not_unregistered (self ):
107+ if not hasattr (sys , "monitoring" ):
108+ self .skipTest ("interpreter has no sys.monitoring (needs 3.12+)" )
109+
110+ out = subprocess .check_output ([sys .executable , "-c" , _MONITORING_DRIVER ], cwd = ROOT )
111+ tool , events = out .decode ("utf-8" ).strip ().splitlines ()
112+
113+ self .assertEqual (tool , "test-tool" ) # still registered - its own owner can still free it
114+ self .assertEqual (events , "0" ) # events cleared to NO_EVENTS, so nothing fires
115+
116+
84117if __name__ == "__main__" :
85118 unittest .main ()
0 commit comments