Skip to content

Commit f02a196

Browse files
committed
Python: Make exception info concept local
1 parent 4196dc2 commit f02a196

File tree

12 files changed

+88
-140
lines changed

12 files changed

+88
-140
lines changed

python/ql/src/semmle/python/Concepts.qll

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -293,54 +293,6 @@ module SqlExecution {
293293
}
294294
}
295295

296-
/**
297-
* A data-flow node that carries information about an error. Such information should
298-
* rarely be exposed directly to the user.
299-
*
300-
* Extend this class to refine existing API models. If you want to model new APIs,
301-
* extend `ErrorInfoSource::Range` instead.
302-
*/
303-
class ErrorInfoSource extends DataFlow::Node {
304-
ErrorInfoSource::Range range;
305-
306-
ErrorInfoSource() { this = range }
307-
}
308-
309-
/** Provides a class for modeling new sources of error information, say via APIs. */
310-
module ErrorInfoSource {
311-
/**
312-
* A data-flow node that carries information about an error. Such information should
313-
* rarely be exposed directly to the user.
314-
*
315-
* Extend this class to model new APIs. If you want to refine existing API models,
316-
* extend `ErrorInfoSource` instead.
317-
*/
318-
abstract class Range extends DataFlow::Node { }
319-
}
320-
321-
/**
322-
* A data-flow node that represents the creation or introduction of an exception.
323-
*
324-
* Extend this class to refine existing API models. If you want to model new APIs,
325-
* extend `ExceptionSource::Range` instead.
326-
*/
327-
class ExceptionSource extends ErrorInfoSource::Range {
328-
ExceptionSource::Range range;
329-
330-
ExceptionSource() { this = range }
331-
}
332-
333-
/** Provides a class for modeling new sources of exceptions, say via APIs. */
334-
module ExceptionSource {
335-
/**
336-
* A data-flow node that represents the creation or introduction of an exception.
337-
*
338-
* Extend this class to model new APIs. If you want to refine existing API models,
339-
* extend `ExceptionSource` instead.
340-
*/
341-
abstract class Range extends DataFlow::Node { }
342-
}
343-
344296
/** Provides classes for modeling HTTP-related APIs. */
345297
module HTTP {
346298
import semmle.python.web.HttpConstants

python/ql/src/semmle/python/frameworks/Stdlib.qll

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,33 +1657,6 @@ private module Stdlib {
16571657
class Sqlite3 extends PEP249Module {
16581658
Sqlite3() { this = sqlite3() }
16591659
}
1660-
1661-
// ---------------------------------------------------------------------------
1662-
// traceback
1663-
// ---------------------------------------------------------------------------
1664-
/** Provides models for the `traceback` module. */
1665-
module traceback {
1666-
private class TracebackFunctionCall extends ErrorInfoSource::Range, DataFlow::CallCfgNode {
1667-
TracebackFunctionCall() {
1668-
this =
1669-
API::moduleImport("traceback")
1670-
.getMember([
1671-
"extract_tb", "extract_stack", "format_list", "format_exception_only",
1672-
"format_exception", "format_exc", "format_tb", "format_stack"
1673-
])
1674-
.getACall()
1675-
}
1676-
}
1677-
}
1678-
}
1679-
1680-
private class CaughtException extends ExceptionSource::Range {
1681-
CaughtException() { this.asExpr() = any(ExceptStmt s).getName() }
1682-
}
1683-
1684-
/** A call to `sys.exc_info` */
1685-
private class SysExcInfoCall extends ErrorInfoSource::Range, DataFlow::CallCfgNode {
1686-
SysExcInfoCall() { this = API::moduleImport("sys").getMember("exc_info").getACall() }
16871660
}
16881661

16891662
// ---------------------------------------------------------------------------
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/** Provides classes representing various sources of information about raised exceptions. */
2+
3+
import python
4+
import semmle.python.dataflow.new.DataFlow
5+
private import semmle.python.ApiGraphs
6+
7+
/**
8+
* A data-flow node that carries information about a raised exception.
9+
* Such information should rarely be exposed directly to the user.
10+
*/
11+
abstract class ExceptionInfo extends DataFlow::Node { }
12+
13+
/** A call to a function from the `traceback` module revealing information about a raised exception. */
14+
private class TracebackFunctionCall extends ExceptionInfo, DataFlow::CallCfgNode {
15+
TracebackFunctionCall() {
16+
this =
17+
API::moduleImport("traceback")
18+
.getMember([
19+
"extract_tb", "extract_stack", "format_list", "format_exception_only",
20+
"format_exception", "format_exc", "format_tb", "format_stack"
21+
])
22+
.getACall()
23+
}
24+
}
25+
26+
/** A caught exception. */
27+
private class CaughtException extends ExceptionInfo {
28+
CaughtException() { this.asExpr() = any(ExceptStmt s).getName() }
29+
}
30+
31+
/** A call to `sys.exc_info`. */
32+
private class SysExcInfoCall extends ExceptionInfo, DataFlow::CallCfgNode {
33+
SysExcInfoCall() { this = API::moduleImport("sys").getMember("exc_info").getACall() }
34+
}

python/ql/src/semmle/python/security/dataflow/StackTraceExposure.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import python
77
import semmle.python.dataflow.new.DataFlow
88
import semmle.python.dataflow.new.TaintTracking
99
import semmle.python.Concepts
10+
private import ExceptionInfo
1011

1112
/**
1213
* A taint-tracking configuration for detecting stack trace exposure.
1314
*/
1415
class StackTraceExposureConfiguration extends TaintTracking::Configuration {
1516
StackTraceExposureConfiguration() { this = "StackTraceExposureConfiguration" }
1617

17-
override predicate isSource(DataFlow::Node source) { source instanceof ErrorInfoSource }
18+
override predicate isSource(DataFlow::Node source) { source instanceof ExceptionInfo }
1819

1920
override predicate isSink(DataFlow::Node sink) {
2021
sink = any(HTTP::Server::HttpResponse response).getBody()

python/ql/test/experimental/library-tests/frameworks/django-v2-v3/manage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def main():
99
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testproj.settings')
1010
try:
1111
from django.core.management import execute_from_command_line
12-
except ImportError as exc: #$ errorInfoSource exceptionSource
12+
except ImportError as exc:
1313
raise ImportError(
1414
"Couldn't import Django. Are you sure it's installed and "
1515
"available on your PYTHONPATH environment variable? Did you "

python/ql/test/experimental/library-tests/frameworks/stdlib-py3/Exceptions.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

python/ql/test/experimental/library-tests/frameworks/stdlib-py3/Stacktrace.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

python/ql/test/experimental/meta/ConceptsTest.qll

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -319,35 +319,3 @@ class SafeAccessCheckTest extends InlineExpectationsTest {
319319
)
320320
}
321321
}
322-
323-
class ErrorInfoSourceTest extends InlineExpectationsTest {
324-
ErrorInfoSourceTest() { this = "ErrorInfoSourceTest" }
325-
326-
override string getARelevantTag() { result = "errorInfoSource" }
327-
328-
override predicate hasActualResult(Location location, string element, string tag, string value) {
329-
exists(location.getFile().getRelativePath()) and
330-
exists(ErrorInfoSource e |
331-
location = e.getLocation() and
332-
element = e.toString() and
333-
value = "" and
334-
tag = "errorInfoSource"
335-
)
336-
}
337-
}
338-
339-
class ExceptionSourceTest extends InlineExpectationsTest {
340-
ExceptionSourceTest() { this = "ExceptionSourceTest" }
341-
342-
override string getARelevantTag() { result = "exceptionSource" }
343-
344-
override predicate hasActualResult(Location location, string element, string tag, string value) {
345-
exists(location.getFile().getRelativePath()) and
346-
exists(ExceptionSource e |
347-
location = e.getLocation() and
348-
element = e.toString() and
349-
value = "" and
350-
tag = "exceptionSource"
351-
)
352-
}
353-
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
import TestUtilities.InlineExpectationsTest
4+
import semmle.python.security.dataflow.ExceptionInfo
5+
6+
class ExceptionInfoTest extends InlineExpectationsTest {
7+
ExceptionInfoTest() { this = "ExceptionInfoTest" }
8+
9+
override string getARelevantTag() { result = "exceptionInfo" }
10+
11+
override predicate hasActualResult(Location location, string element, string tag, string value) {
12+
exists(location.getFile().getRelativePath()) and
13+
exists(ExceptionInfo e |
14+
location = e.getLocation() and
15+
element = e.toString() and
16+
value = "" and
17+
tag = "exceptionInfo"
18+
)
19+
}
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
try:
2+
1+2
3+
except Exception as e: #$ exceptionInfo
4+
e
5+
6+
def test_exception():
7+
try:
8+
1+2
9+
except Exception as e: #$ exceptionInfo
10+
e

0 commit comments

Comments
 (0)