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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/catch_exception.ql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ import python

from ExceptStmt ex, ClassValue cls
where
cls.getName() = "MyExceptionClass" and
ex.getType().pointsTo(cls)
cls.getName() = "MyExceptionClass" and
ex.getType().pointsTo(cls)
select ex
6 changes: 3 additions & 3 deletions python/ql/examples/snippets/conditional_expression.ql
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import python

from IfExp e, ClassObject cls1, ClassObject cls2
where
e.getBody().refersTo(_, cls1, _) and
e.getOrelse().refersTo(_, cls2, _) and
cls1 != cls2
e.getBody().refersTo(_, cls1, _) and
e.getOrelse().refersTo(_, cls2, _) and
cls1 != cls2
select e
8 changes: 4 additions & 4 deletions python/ql/examples/snippets/emptythen.ql
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import python

from If i
where
not exists(Stmt s |
i.getStmt(_) = s and
not s instanceof Pass
)
not exists(Stmt s |
i.getStmt(_) = s and
not s instanceof Pass
)
select i
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/extend_class.ql
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ import python

from ClassObject sub, ClassObject base
where
base.getName() = "MyClass" and
sub.getABaseType() = base
base.getName() = "MyClass" and
sub.getABaseType() = base
select sub
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/method_call.ql
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ import python

from AstNode call, PythonFunctionValue method
where
method.getQualifiedName() = "MyClass.methodName" and
method.getACall().getNode() = call
method.getQualifiedName() = "MyClass.methodName" and
method.getACall().getNode() = call
select call
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/new_instance.ql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ import python

from Call new, ClassValue cls
where
cls.getName() = "MyClass" and
new.getFunc().pointsTo(cls)
cls.getName() = "MyClass" and
new.getFunc().pointsTo(cls)
select new
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/override_method.ql
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ import python

from FunctionObject override, FunctionObject base
where
base.getQualifiedName() = "MyClass.methodName" and
override.overrides(base)
base.getQualifiedName() = "MyClass.methodName" and
override.overrides(base)
select override
10 changes: 5 additions & 5 deletions python/ql/examples/snippets/print.ql
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import python

from AstNode print
where
/* Python 2 without `from __future__ import print_function` */
print instanceof Print
or
/* Python 3 or with `from __future__ import print_function` */
print.(Call).getFunc().pointsTo(Value::named("print"))
/* Python 2 without `from __future__ import print_function` */
print instanceof Print
or
/* Python 3 or with `from __future__ import print_function` */
print.(Call).getFunc().pointsTo(Value::named("print"))
select print
8 changes: 4 additions & 4 deletions python/ql/examples/snippets/private_access.ql
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import python

predicate is_private(Attribute a) {
a.getName().matches("\\_%") and
not a.getName().matches("\\_\\_%\\_\\_")
a.getName().matches("\\_%") and
not a.getName().matches("\\_\\_%\\_\\_")
}

from Attribute access
where
is_private(access) and
not access.getObject().(Name).getId() = "self"
is_private(access) and
not access.getObject().(Name).getId() = "self"
select access
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/raise_exception.ql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ import python

from Raise raise, ClassValue ex
where
ex.getName() = "AnException" and
raise.getException().pointsTo(ex.getASuperType())
ex.getName() = "AnException" and
raise.getException().pointsTo(ex.getASuperType())
select raise, "Don't raise instances of 'AnException'"
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/store_none.ql
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ import python

from SubscriptNode store
where
store.isStore() and
store.getIndex().pointsTo(Value::named("None"))
store.isStore() and
store.getIndex().pointsTo(Value::named("None"))
select store
4 changes: 2 additions & 2 deletions python/ql/examples/snippets/tryfinally.ql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ import python

from Try t
where
exists(t.getFinalbody()) and
not exists(t.getAHandler())
exists(t.getFinalbody()) and
not exists(t.getAHandler())
select t
240 changes: 120 additions & 120 deletions python/ql/src/Classes/ClassAttributes.qll
Original file line number Diff line number Diff line change
Expand Up @@ -3,140 +3,140 @@ private import semmle.python.pointsto.PointsTo

/** Helper class for UndefinedClassAttribute.ql and MaybeUndefinedClassAttribute.ql */
class CheckClass extends ClassObject {
private predicate ofInterest() {
not this.unknowableAttributes() and
not this.getPyClass().isProbableMixin() and
this.getPyClass().isPublic() and
not this.getPyClass().getScope() instanceof Function and
not this.probablyAbstract() and
not this.declaresAttribute("__new__") and
not this.selfDictAssigns() and
not this.lookupAttribute("__getattribute__") != object_getattribute() and
not this.hasAttribute("__getattr__") and
not this.selfSetattr() and
/* If class overrides object.__init__, but we can't resolve it to a Python function then give up */
forall(ClassObject sup |
sup = this.getAnImproperSuperType() and
sup.declaresAttribute("__init__") and
not sup = theObjectType()
|
sup.declaredAttribute("__init__") instanceof PyFunctionObject
)
}
private predicate ofInterest() {
not this.unknowableAttributes() and
not this.getPyClass().isProbableMixin() and
this.getPyClass().isPublic() and
not this.getPyClass().getScope() instanceof Function and
not this.probablyAbstract() and
not this.declaresAttribute("__new__") and
not this.selfDictAssigns() and
not this.lookupAttribute("__getattribute__") != object_getattribute() and
not this.hasAttribute("__getattr__") and
not this.selfSetattr() and
/* If class overrides object.__init__, but we can't resolve it to a Python function then give up */
forall(ClassObject sup |
sup = this.getAnImproperSuperType() and
sup.declaresAttribute("__init__") and
not sup = theObjectType()
|
sup.declaredAttribute("__init__") instanceof PyFunctionObject
)
}

predicate alwaysDefines(string name) {
auto_name(name) or
this.hasAttribute(name) or
this.getAnImproperSuperType().assignedInInit(name) or
this.getMetaClass().assignedInInit(name)
}
predicate alwaysDefines(string name) {
auto_name(name) or
this.hasAttribute(name) or
this.getAnImproperSuperType().assignedInInit(name) or
this.getMetaClass().assignedInInit(name)
}

predicate sometimesDefines(string name) {
this.alwaysDefines(name)
or
exists(SelfAttributeStore sa |
sa.getScope().getScope+() = this.getAnImproperSuperType().getPyClass()
|
name = sa.getName()
)
}
predicate sometimesDefines(string name) {
this.alwaysDefines(name)
or
exists(SelfAttributeStore sa |
sa.getScope().getScope+() = this.getAnImproperSuperType().getPyClass()
|
name = sa.getName()
)
}

private predicate selfDictAssigns() {
exists(Assign a, SelfAttributeRead self_dict, Subscript sub |
self_dict.getName() = "__dict__" and
(
self_dict = sub.getObject()
or
/* Indirect assignment via temporary variable */
exists(SsaVariable v |
v.getAUse() = sub.getObject().getAFlowNode() and
v.getDefinition().(DefinitionNode).getValue() = self_dict.getAFlowNode()
)
) and
a.getATarget() = sub and
exists(FunctionObject meth |
meth = this.lookupAttribute(_) and a.getScope() = meth.getFunction()
)
private predicate selfDictAssigns() {
exists(Assign a, SelfAttributeRead self_dict, Subscript sub |
self_dict.getName() = "__dict__" and
(
self_dict = sub.getObject()
or
/* Indirect assignment via temporary variable */
exists(SsaVariable v |
v.getAUse() = sub.getObject().getAFlowNode() and
v.getDefinition().(DefinitionNode).getValue() = self_dict.getAFlowNode()
)
}
) and
a.getATarget() = sub and
exists(FunctionObject meth |
meth = this.lookupAttribute(_) and a.getScope() = meth.getFunction()
)
)
}

pragma[nomagic]
private predicate monkeyPatched(string name) {
exists(Attribute a |
a.getCtx() instanceof Store and
PointsTo::points_to(a.getObject().getAFlowNode(), _, this, _, _) and
a.getName() = name
)
}
pragma[nomagic]
private predicate monkeyPatched(string name) {
exists(Attribute a |
a.getCtx() instanceof Store and
PointsTo::points_to(a.getObject().getAFlowNode(), _, this, _, _) and
a.getName() = name
)
}

private predicate selfSetattr() {
exists(Call c, Name setattr, Name self, Function method |
(
method.getScope() = this.getPyClass() or
method.getScope() = this.getASuperType().getPyClass()
) and
c.getScope() = method and
c.getFunc() = setattr and
setattr.getId() = "setattr" and
c.getArg(0) = self and
self.getId() = "self"
)
}
private predicate selfSetattr() {
exists(Call c, Name setattr, Name self, Function method |
(
method.getScope() = this.getPyClass() or
method.getScope() = this.getASuperType().getPyClass()
) and
c.getScope() = method and
c.getFunc() = setattr and
setattr.getId() = "setattr" and
c.getArg(0) = self and
self.getId() = "self"
)
}

predicate interestingUndefined(SelfAttributeRead a) {
exists(string name | name = a.getName() |
interestingContext(a, name) and
not this.definedInBlock(a.getAFlowNode().getBasicBlock(), name)
)
}
predicate interestingUndefined(SelfAttributeRead a) {
exists(string name | name = a.getName() |
interestingContext(a, name) and
not this.definedInBlock(a.getAFlowNode().getBasicBlock(), name)
)
}

private predicate interestingContext(SelfAttributeRead a, string name) {
name = a.getName() and
this.ofInterest() and
this.getPyClass() = a.getScope().getScope() and
not a.locallyDefined() and
not a.guardedByHasattr() and
a.getScope().isPublic() and
not this.monkeyPatched(name) and
not attribute_assigned_in_method(lookupAttribute("setUp"), name)
}
private predicate interestingContext(SelfAttributeRead a, string name) {
name = a.getName() and
this.ofInterest() and
this.getPyClass() = a.getScope().getScope() and
not a.locallyDefined() and
not a.guardedByHasattr() and
a.getScope().isPublic() and
not this.monkeyPatched(name) and
not attribute_assigned_in_method(lookupAttribute("setUp"), name)
}

private predicate probablyAbstract() {
this.getName().matches("Abstract%")
or
this.isAbstract()
}
private predicate probablyAbstract() {
this.getName().matches("Abstract%")
or
this.isAbstract()
}

pragma[nomagic]
private predicate definitionInBlock(BasicBlock b, string name) {
exists(SelfAttributeStore sa |
sa.getAFlowNode().getBasicBlock() = b and
sa.getName() = name and
sa.getClass() = this.getPyClass()
)
or
exists(FunctionObject method | this.lookupAttribute(_) = method |
attribute_assigned_in_method(method, name) and
b = method.getACall().getBasicBlock()
)
}
pragma[nomagic]
private predicate definitionInBlock(BasicBlock b, string name) {
exists(SelfAttributeStore sa |
sa.getAFlowNode().getBasicBlock() = b and
sa.getName() = name and
sa.getClass() = this.getPyClass()
)
or
exists(FunctionObject method | this.lookupAttribute(_) = method |
attribute_assigned_in_method(method, name) and
b = method.getACall().getBasicBlock()
)
}

pragma[nomagic]
private predicate definedInBlock(BasicBlock b, string name) {
// manual specialisation: this is only called from interestingUndefined,
// so we can push the context in from there, which must apply to a
// SelfAttributeRead in the same scope
exists(SelfAttributeRead a | a.getScope() = b.getScope() and name = a.getName() |
interestingContext(a, name)
) and
this.definitionInBlock(b, name)
or
exists(BasicBlock prev | this.definedInBlock(prev, name) and prev.getASuccessor() = b)
}
pragma[nomagic]
private predicate definedInBlock(BasicBlock b, string name) {
// manual specialisation: this is only called from interestingUndefined,
// so we can push the context in from there, which must apply to a
// SelfAttributeRead in the same scope
exists(SelfAttributeRead a | a.getScope() = b.getScope() and name = a.getName() |
interestingContext(a, name)
) and
this.definitionInBlock(b, name)
or
exists(BasicBlock prev | this.definedInBlock(prev, name) and prev.getASuccessor() = b)
}
}

private Object object_getattribute() {
result.asBuiltin() = theObjectType().asBuiltin().getMember("__getattribute__")
result.asBuiltin() = theObjectType().asBuiltin().getMember("__getattribute__")
}

private predicate auto_name(string name) { name = "__class__" or name = "__dict__" }
Loading