Skip to content

Commit 0217451

Browse files
authored
Merge pull request #789 from markshannon/python-points-to-extension-enhancement
Python: Internal points-to extension enhancement.
2 parents eaa5a5f + 19c4351 commit 0217451

File tree

10 files changed

+111
-5
lines changed

10 files changed

+111
-5
lines changed

change-notes/1.20/analysis-python.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
> Changes that affect alerts in many files or from many queries
77
> For example, changes to file classification
8+
9+
The constants `MULTILINE` and `VERBOSE` in `re` module, are now understood for Python 3.6 and upward.
10+
Removes false positives seen when using Python 3.6, but not when using earlier versions.
11+
812
## New queries
913

1014
| **Query** | **Tags** | **Purpose** |

python/ql/src/semmle/python/pointsto/PointsTo.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@ module PointsTo {
266266
SSA::ssa_definition_points_to(var.getDefinition(), context, value, cls, origin)
267267
}
268268

269-
270269
}
271270

272271
predicate name_maybe_imported_from(ModuleObject mod, string name) {
@@ -635,6 +634,11 @@ module PointsTo {
635634
)
636635
or
637636
points_to(f.getObject(), context, unknownValue(), theUnknownType(), origin) and value = unknownValue() and cls = theUnknownType()
637+
or
638+
exists(CustomPointsToAttribute object, string name |
639+
points_to(f.getObject(name), context, object, _, _) and
640+
object.attributePointsTo(name, value, cls, origin)
641+
)
638642
}
639643

640644
/** Holds if `f` is an expression node `tval if cond else fval` and points to `(value, cls, origin)`. */

python/ql/src/semmle/python/regex.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ string mode_from_mode_object(Object obj) {
4040
result = "MULTILINE" or result = "DOTALL" or result = "UNICODE" or
4141
result = "VERBOSE"
4242
) and
43-
ModuleObject::named("re").getAttribute(result) = obj
43+
ModuleObject::named("sre_constants").getAttribute("SRE_FLAG_" + result) = obj
4444
or
4545
exists(BinaryExpr be, Object sub | obj.getOrigin() = be |
4646
be.getOp() instanceof BitOr and

python/ql/src/semmle/python/types/Extensions.qll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ abstract class CustomPointsToOriginFact extends CustomPointsToFact {
3434

3535
}
3636

37+
/** INTERNAL -- Do not use */
38+
abstract class CustomPointsToAttribute extends Object {
39+
40+
abstract predicate attributePointsTo(string name, Object value, ClassObject cls, ControlFlowNode origin);
41+
42+
}
43+
3744
/* An example */
3845

3946
/** Any variable iterating over range or xrange must be an integer */
@@ -56,4 +63,21 @@ class RangeIterationVariableFact extends CustomPointsToFact {
5663
}
5764
}
5865

66+
/* Python 3.6+ regex module constants */
67+
68+
class ReModulePointToExtension extends CustomPointsToAttribute {
69+
70+
ReModulePointToExtension() {
71+
this.(ModuleObject).getName() = "re"
72+
}
73+
74+
override predicate attributePointsTo(string name, Object value, ClassObject cls, ControlFlowNode origin) {
75+
exists(ModuleObject sre_constants |
76+
sre_constants.getName() = "sre_constants" and
77+
sre_constants.attributeRefersTo("SRE_FLAG_" + name, value, cls, origin)
78+
)
79+
}
80+
}
81+
82+
5983

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
| test.py:4:1:4:3 | ControlFlowNode for one | int 1 |
2+
| test.py:5:1:5:3 | ControlFlowNode for two | int 2 |
3+
| test.py:8:1:8:1 | ControlFlowNode for IntegerLiteral | int 1 |
4+
| test.py:8:1:8:7 | ControlFlowNode for Tuple | Tuple |
5+
| test.py:8:3:8:3 | ControlFlowNode for IntegerLiteral | int 2 |
6+
| test.py:8:5:8:5 | ControlFlowNode for IntegerLiteral | int 3 |
7+
| test.py:8:7:8:7 | ControlFlowNode for IntegerLiteral | int 4 |
8+
| test.py:10:1:10:2 | ControlFlowNode for a3 | int 3 |
9+
| test.py:10:6:10:7 | ControlFlowNode for Tuple | Tuple |
10+
| test.py:10:6:10:13 | ControlFlowNode for Attribute | int 3 |
11+
| test.py:11:1:11:2 | ControlFlowNode for a4 | int 4 |
12+
| test.py:11:6:11:10 | ControlFlowNode for False | bool False |
13+
| test.py:11:6:11:15 | ControlFlowNode for Attribute | int 4 |
14+
| test.py:13:1:13:2 | ControlFlowNode for a3 | int 3 |
15+
| test.py:14:1:14:2 | ControlFlowNode for a4 | int 4 |
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
3+
import python
4+
5+
private import semmle.python.types.Extensions
6+
7+
8+
class CfgExtension extends CustomPointsToOriginFact {
9+
10+
CfgExtension() {
11+
this.(NameNode).getId() = "one"
12+
or
13+
this.(NameNode).getId() = "two"
14+
}
15+
16+
override predicate pointsTo(Object value, ClassObject cls) {
17+
cls = theIntType() and
18+
(
19+
this.(NameNode).getId() = "one" and value.(NumericObject).intValue() = 1
20+
or
21+
this.(NameNode).getId() = "two" and value.(NumericObject).intValue() = 2
22+
)
23+
}
24+
}
25+
26+
class AttributeExtension extends CustomPointsToAttribute {
27+
28+
AttributeExtension() { this = this }
29+
30+
override predicate attributePointsTo(string name, Object value, ClassObject cls, ControlFlowNode origin) {
31+
cls = theIntType() and origin = any(Module m).getEntryNode() and
32+
(
33+
name = "three" and value.(NumericObject).intValue() = 3
34+
or
35+
name = "four" and value.(NumericObject).intValue() = 4
36+
)
37+
}
38+
39+
}
40+
41+
from ControlFlowNode f, Object o
42+
where f.getLocation().getFile().getBaseName() = "test.py" and f.refersTo(o)
43+
select f, o.toString()
44+
45+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
#Magical values
3+
4+
one
5+
two
6+
7+
#Make sure values exist in DB
8+
1,2,3,4
9+
10+
a3 = ().three
11+
a4 = False.four
12+
13+
a3
14+
a4

python/ql/test/library-tests/regex/Characters.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import python
88
import semmle.python.regex
99

1010
from Regex r, int start, int end
11-
where r.character(start, end)
11+
where r.character(start, end) and r.getLocation().getFile().getBaseName() = "test.py"
1212
select r.getText(), start, end
1313

1414

python/ql/test/library-tests/regex/FirstLast.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ predicate part(Regex r, int start, int end, string kind) {
1010
}
1111

1212
from Regex r, int start, int end, string kind
13-
where part(r, start, end, kind)
13+
where part(r, start, end, kind) and r.getLocation().getFile().getBaseName() = "test.py"
1414
select r.getText(), kind, start, end

python/ql/test/library-tests/regex/Regex.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ predicate part(Regex r, int start, int end, string kind) {
2222
}
2323

2424
from Regex r, int start, int end, string kind
25-
where part(r, start, end, kind)
25+
where part(r, start, end, kind) and r.getLocation().getFile().getBaseName() = "test.py"
2626
select r.getText(), kind, start, end

0 commit comments

Comments
 (0)