Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/core/profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ def profile(profileOutputFile=None):
os.remove(profileOutputFile)

# Start sqlmap main function and generate a raw profile file
cProfile.run("start()", profileOutputFile)
# Note: run() would exec inside __main__, which on pip installs is the console script, not sqlmap.py
from lib.controller.controller import start
cProfile.runctx("start()", {"start": start}, {}, profileOutputFile)

infoMsg = "execution profiled and stored into file '%s' (e.g. 'gprof2dot -f pstats %s | dot -Tpng -o /tmp/sqlmap_profile.png')" % (profileOutputFile, profileOutputFile)
logger.info(infoMsg)
2 changes: 1 addition & 1 deletion lib/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from thirdparty import six

# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.10.8.22"
VERSION = "1.10.8.23"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
Expand Down
1 change: 0 additions & 1 deletion sqlmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ def main():
from lib.controller.controller import start
if conf.profile:
from lib.core.profiling import profile
globals()["start"] = start
profile()
else:
try:
Expand Down
59 changes: 59 additions & 0 deletions tests/test_profiling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python

"""
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission

Switch '--profile' (lib/core/profiling.py). The profiled statement must resolve
'start' from an explicit namespace: on pip installs __main__ is the console
script, not sqlmap.py, so relying on it raised NameError (#6096). This test runs
under a unittest __main__ that has no 'start' either, so it covers that case.
"""

import os
import pstats
import shutil
import sys
import tempfile
import unittest

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from _testutils import bootstrap
bootstrap()

import lib.controller.controller as controller
from lib.core.profiling import profile


class TestProfiling(unittest.TestCase):
def setUp(self):
self._saved = controller.start
self._dir = tempfile.mkdtemp()
self._out = os.path.join(self._dir, "sqlmap_profile.raw")

def tearDown(self):
controller.start = self._saved
shutil.rmtree(self._dir, ignore_errors=True)

def test_profile_does_not_need_start_in_main(self):
calls = []
controller.start = lambda *args, **kwargs: calls.append(True)

profile(self._out)

self.assertEqual(calls, [True], msg="start() was never run under the profiler")
self.assertTrue(os.path.exists(self._out), msg="no raw profile written")
self.assertTrue(pstats.Stats(self._out).stats, msg="raw profile holds no stats")

def test_profile_overwrites_a_stale_output_file(self):
controller.start = lambda *args, **kwargs: None

with open(self._out, "wb") as f:
f.write(b"not a pstats file")

profile(self._out)
self.assertTrue(pstats.Stats(self._out).stats)


if __name__ == "__main__":
unittest.main()