mirror of
https://github.com/github/codeql.git
synced 2025-12-19 18:33:16 +01:00
147 lines
5.2 KiB
Plaintext
147 lines
5.2 KiB
Plaintext
import python
|
|
import semmle.python.pointsto.PointsTo
|
|
import semmle.python.objects.ObjectInternal
|
|
|
|
predicate ssa_consistency(string clsname, string problem, string what) {
|
|
/* Exactly one definition of each SSA variable */
|
|
exists(EssaVariable var | clsname = var.getAQlClass() |
|
|
/* Exactly one definition of each SSA variable */
|
|
count(var.getDefinition()) != 1 and
|
|
problem = " has " + count(var.getDefinition()) + " definitions." and
|
|
what = "SSA variable " + var.getSourceVariable().getName()
|
|
or
|
|
/* Backing variable */
|
|
not exists(var.getSourceVariable()) and
|
|
problem = "An SSA variable has no backing variable." and
|
|
what = "An SSA variable"
|
|
or
|
|
count(var.getSourceVariable()) != 1 and
|
|
problem =
|
|
var.getSourceVariable().getName() + " has " + count(var.getSourceVariable()) +
|
|
" backing variables." and
|
|
what = "SSA variable " + var.getSourceVariable().getName()
|
|
)
|
|
or
|
|
/* Exactly one location */
|
|
exists(EssaDefinition def |
|
|
clsname = def.getAQlClass() and
|
|
what =
|
|
"SSA Definition " + def.getSourceVariable().getName() + " in " +
|
|
def.getSourceVariable().(Variable).getScope().getName() and
|
|
count(def.getLocation()) != 1 and
|
|
problem = " has " + count(def.getLocation()) + " locations"
|
|
)
|
|
or
|
|
/* Must have a source variable */
|
|
exists(EssaDefinition def |
|
|
clsname = def.getAQlClass() and
|
|
not exists(def.getSourceVariable()) and
|
|
what = " at " + def.getLocation() and
|
|
problem = "has not source variable"
|
|
)
|
|
or
|
|
/* Variables must have exactly one representation */
|
|
exists(EssaVariable var |
|
|
clsname = var.getAQlClass() and
|
|
what =
|
|
"SSA variable " + var.getSourceVariable().getName() + " defined at " +
|
|
var.getDefinition().getLocation() and
|
|
count(var.getRepresentation()) != 1 and
|
|
problem = " has " + count(var.getRepresentation()) + " representations"
|
|
)
|
|
or
|
|
/* Definitions must have exactly one representation */
|
|
exists(EssaDefinition def |
|
|
clsname = def.getAQlClass() and
|
|
what = "SSA definition " + def.getSourceVariable().getName() + " at " + def.getLocation() and
|
|
count(def.getRepresentation()) != 1 and
|
|
problem =
|
|
" has " + count(def.getRepresentation()) + " representations: " + def.getRepresentation()
|
|
)
|
|
or
|
|
/* Refinements must have exactly one input */
|
|
exists(EssaNodeRefinement ref |
|
|
clsname = ref.getAQlClass() and
|
|
what = "Refinement " + ref.getSourceVariable().getName() + " at " + ref.getLocation() and
|
|
count(ref.getInput()) != 1 and
|
|
problem = " has " + count(ref.getInput()) + " inputs: " + ref.getInput().getRepresentation()
|
|
)
|
|
or
|
|
/*
|
|
* Ideally filter nodes should have exactly one input, but it is not a big deal
|
|
* if we prune away the input, leaving it with none.
|
|
*/
|
|
|
|
exists(EssaEdgeRefinement def |
|
|
clsname = def.getAQlClass() and
|
|
what = def.getSourceVariable().getName() + " at " + def.getLocation()
|
|
|
|
|
count(def.getInput()) > 1 and problem = " has " + count(def.getInput()) + " inputs."
|
|
)
|
|
or
|
|
/* Each use has only one reaching SSA variable */
|
|
exists(ControlFlowNode use, SsaSourceVariable v, int c |
|
|
c = strictcount(EssaVariable s | s.getAUse() = use and s.getSourceVariable() = v) and
|
|
clsname = use.getAQlClass() and
|
|
c != 1 and
|
|
what = use + " at " + use.getLocation() and
|
|
problem = " has " + c + " SSA variables reaching."
|
|
)
|
|
or
|
|
/* Python-specific subclasses of EssaDefinitions should be disjoint and complete */
|
|
exists(EssaDefinition def |
|
|
clsname = def.getAQlClass() and
|
|
what = def.getVariable().getName() + " at " + def.getLocation() and
|
|
problem = "has non-disjoint subclasses"
|
|
|
|
|
strictcount(def.getAQlClass()) > 2
|
|
or
|
|
/* OK if method call and argument overlap: `x.foo(x)` */
|
|
strictcount(def.getAQlClass()) > 1 and
|
|
not clsname = "ArgumentRefinement" and
|
|
not clsname = "SelfCallsiteRefinement"
|
|
)
|
|
or
|
|
exists(EssaDefinition def |
|
|
clsname = def.getAQlClass() and
|
|
clsname.matches("Essa%") and
|
|
what = " at " + def.getLocation() and
|
|
problem = "not covered by Python-specific subclass."
|
|
)
|
|
or
|
|
// All modules should have __name__
|
|
exists(Module m |
|
|
what = " at " + m.getLocation() and
|
|
clsname = "Module"
|
|
|
|
|
not exists(m.getName()) and
|
|
problem = "does not have a name"
|
|
or
|
|
not m.isPackage() and
|
|
not exists(Variable v | v.getId() = "__name__" and v.getScope() = m) and
|
|
problem = "does not have a __name__ variable"
|
|
or
|
|
not m.isPackage() and
|
|
not exists(EssaNodeDefinition def |
|
|
def.getDefiningNode().getScope() = m and
|
|
def.getVariable().getName() = "__name__"
|
|
) and
|
|
problem = "does not have an ImplicitModuleNameDefinition"
|
|
)
|
|
}
|
|
|
|
predicate undefined_consistency(string clsname, string problem, string what) {
|
|
/* Variables may be undefined, but values cannot be */
|
|
exists(ControlFlowNode f |
|
|
PointsToInternal::pointsTo(f, _, ObjectInternal::undefined(), _) and
|
|
clsname = f.getAQlClass() and
|
|
not clsname = "AnyNode" and
|
|
problem = " points-to an undefined variable" and
|
|
what = f.toString()
|
|
)
|
|
}
|
|
|
|
from string clsname, string problem, string what
|
|
where ssa_consistency(clsname, problem, what) or undefined_consistency(clsname, problem, what)
|
|
select clsname, what, problem
|