mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
Merge pull request #1303 from jbj/hasQualifiedName
C++: Fix `getQualifiedName` performance issues
This commit is contained in:
@@ -13,7 +13,7 @@ import semmle.code.cpp.pointsto.PointsTo
|
||||
import Negativity
|
||||
|
||||
predicate closeCall(FunctionCall fc, Variable v) {
|
||||
fc.getTarget().hasQualifiedName("close") and v.getAnAccess() = fc.getArgument(0)
|
||||
fc.getTarget().hasGlobalName("close") and v.getAnAccess() = fc.getArgument(0)
|
||||
or
|
||||
exists(FunctionCall midcall, Function mid, int arg |
|
||||
fc.getArgument(arg) = v.getAnAccess() and
|
||||
|
||||
@@ -13,7 +13,7 @@ import semmle.code.cpp.pointsto.PointsTo
|
||||
|
||||
predicate closed(Expr e) {
|
||||
exists(FunctionCall fc |
|
||||
fc.getTarget().hasQualifiedName("close") and
|
||||
fc.getTarget().hasGlobalName("close") and
|
||||
fc.getArgument(0) = e
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ predicate useFunc(GlobalVariable v, Function f) {
|
||||
}
|
||||
|
||||
predicate uninitialisedBefore(GlobalVariable v, Function f) {
|
||||
f.hasQualifiedName("main")
|
||||
f.hasGlobalName("main")
|
||||
or
|
||||
exists(Call call, Function g |
|
||||
uninitialisedBefore(v, g) and
|
||||
|
||||
@@ -20,7 +20,7 @@ predicate global(GlobalVariable v) {
|
||||
}
|
||||
|
||||
predicate mainCalled(Function f) {
|
||||
f.getQualifiedName() = "main"
|
||||
f.hasGlobalName("main")
|
||||
or
|
||||
exists(Function caller | mainCalled(caller) and allCalls(caller, f))
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ predicate allocCallOrIndirect(Expr e) {
|
||||
* can cause memory leaks.
|
||||
*/
|
||||
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified) {
|
||||
reallocCall.getTarget().hasQualifiedName("realloc") and
|
||||
reallocCall.getTarget().hasGlobalName("realloc") and
|
||||
reallocCall.getArgument(0) = v.getAnAccess() and
|
||||
(
|
||||
exists(Variable newV, ControlFlowNode node |
|
||||
@@ -82,7 +82,7 @@ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode
|
||||
predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
|
||||
// direct free call
|
||||
freeCall(n, v.getAnAccess()) and
|
||||
not n.(FunctionCall).getTarget().hasQualifiedName("realloc")
|
||||
not n.(FunctionCall).getTarget().hasGlobalName("realloc")
|
||||
or
|
||||
// verified realloc call
|
||||
verifiedRealloc(_, v, n)
|
||||
|
||||
@@ -14,8 +14,8 @@ import cpp
|
||||
|
||||
class MallocCall extends FunctionCall {
|
||||
MallocCall() {
|
||||
this.getTarget().hasQualifiedName("malloc") or
|
||||
this.getTarget().hasQualifiedName("std::malloc")
|
||||
this.getTarget().hasGlobalName("malloc") or
|
||||
this.getTarget().hasQualifiedName("std", "malloc")
|
||||
}
|
||||
|
||||
Expr getAllocatedSize() {
|
||||
@@ -36,12 +36,12 @@ predicate spaceProblem(FunctionCall append, string msg) {
|
||||
malloc.getAllocatedSize() = add and
|
||||
buffer.getAnAccess() = strlen.getStringExpr() and
|
||||
(
|
||||
insert.getTarget().hasQualifiedName("strcpy") or
|
||||
insert.getTarget().hasQualifiedName("strncpy")
|
||||
insert.getTarget().hasGlobalName("strcpy") or
|
||||
insert.getTarget().hasGlobalName("strncpy")
|
||||
) and
|
||||
(
|
||||
append.getTarget().hasQualifiedName("strcat") or
|
||||
append.getTarget().hasQualifiedName("strncat")
|
||||
append.getTarget().hasGlobalName("strcat") or
|
||||
append.getTarget().hasGlobalName("strncat")
|
||||
) and
|
||||
malloc.getASuccessor+() = insert and
|
||||
insert.getArgument(1) = buffer.getAnAccess() and
|
||||
|
||||
@@ -25,7 +25,7 @@ import semmle.code.cpp.security.TaintTracking
|
||||
predicate sourceSized(FunctionCall fc, Expr src) {
|
||||
exists(string name |
|
||||
(name = "strncpy" or name = "strncat" or name = "memcpy" or name = "memmove") and
|
||||
fc.getTarget().hasQualifiedName(name)
|
||||
fc.getTarget().hasGlobalName(name)
|
||||
) and
|
||||
exists(Expr dest, Expr size, Variable v |
|
||||
fc.getArgument(0) = dest and
|
||||
|
||||
@@ -59,21 +59,21 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
|
||||
}
|
||||
|
||||
predicate bufferAndSizeFunction(Function f, int buf, int size) {
|
||||
f.hasQualifiedName("read") and buf = 1 and size = 2
|
||||
f.hasGlobalName("read") and buf = 1 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("fgets") and buf = 0 and size = 1
|
||||
f.hasGlobalName("fgets") and buf = 0 and size = 1
|
||||
or
|
||||
f.hasQualifiedName("strncpy") and buf = 0 and size = 2
|
||||
f.hasGlobalName("strncpy") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("strncat") and buf = 0 and size = 2
|
||||
f.hasGlobalName("strncat") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("memcpy") and buf = 0 and size = 2
|
||||
f.hasGlobalName("memcpy") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("memmove") and buf = 0 and size = 2
|
||||
f.hasGlobalName("memmove") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("snprintf") and buf = 0 and size = 1
|
||||
f.hasGlobalName("snprintf") and buf = 0 and size = 1
|
||||
or
|
||||
f.hasQualifiedName("vsnprintf") and buf = 0 and size = 1
|
||||
f.hasGlobalName("vsnprintf") and buf = 0 and size = 1
|
||||
}
|
||||
|
||||
class CallWithBufferSize extends FunctionCall {
|
||||
|
||||
@@ -17,12 +17,12 @@ import cpp
|
||||
class Allocation extends FunctionCall {
|
||||
Allocation() {
|
||||
exists(string name |
|
||||
this.getTarget().hasQualifiedName(name) and
|
||||
this.getTarget().hasGlobalName(name) and
|
||||
(name = "malloc" or name = "calloc" or name = "realloc")
|
||||
)
|
||||
}
|
||||
|
||||
string getName() { result = this.getTarget().getQualifiedName() }
|
||||
private string getName() { this.getTarget().hasGlobalName(result) }
|
||||
|
||||
int getSize() {
|
||||
this.getName() = "malloc" and
|
||||
|
||||
@@ -17,12 +17,12 @@ import cpp
|
||||
class Allocation extends FunctionCall {
|
||||
Allocation() {
|
||||
exists(string name |
|
||||
this.getTarget().hasQualifiedName(name) and
|
||||
this.getTarget().hasGlobalName(name) and
|
||||
(name = "malloc" or name = "calloc" or name = "realloc")
|
||||
)
|
||||
}
|
||||
|
||||
string getName() { result = this.getTarget().getQualifiedName() }
|
||||
private string getName() { this.getTarget().hasGlobalName(result) }
|
||||
|
||||
int getSize() {
|
||||
this.getName() = "malloc" and
|
||||
|
||||
@@ -16,7 +16,7 @@ import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
predicate isFreeExpr(Expr e, LocalScopeVariable v) {
|
||||
exists(VariableAccess va | va.getTarget() = v |
|
||||
exists(FunctionCall fc | fc = e |
|
||||
fc.getTarget().hasQualifiedName("free") and
|
||||
fc.getTarget().hasGlobalName("free") and
|
||||
va = fc.getArgument(0)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -32,7 +32,7 @@ class Options extends string
|
||||
*/
|
||||
predicate overrideReturnsNull(Call call) {
|
||||
// Used in CVS:
|
||||
call.(FunctionCall).getTarget().hasQualifiedName("Xstrdup")
|
||||
call.(FunctionCall).getTarget().hasGlobalName("Xstrdup")
|
||||
or
|
||||
CustomOptions::overrideReturnsNull(call) // old Options.qll
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class Options extends string
|
||||
*/
|
||||
predicate returnsNull(Call call) {
|
||||
// Used in CVS:
|
||||
call.(FunctionCall).getTarget().hasQualifiedName("Xstrdup") and
|
||||
call.(FunctionCall).getTarget().hasGlobalName("Xstrdup") and
|
||||
nullValue(call.getArgument(0))
|
||||
or
|
||||
CustomOptions::returnsNull(call) // old Options.qll
|
||||
@@ -61,7 +61,7 @@ class Options extends string
|
||||
*/
|
||||
predicate exits(Function f) {
|
||||
f.getAnAttribute().hasName("noreturn") or
|
||||
exists(string name | f.getQualifiedName() = name |
|
||||
exists(string name | f.hasGlobalName(name) |
|
||||
name = "exit" or
|
||||
name = "_exit" or
|
||||
name = "abort" or
|
||||
@@ -92,7 +92,7 @@ class Options extends string
|
||||
* By default holds only for `fgets`.
|
||||
*/
|
||||
predicate alwaysCheckReturnValue(Function f) {
|
||||
f.hasQualifiedName("fgets") or
|
||||
f.hasGlobalName("fgets") or
|
||||
CustomOptions::alwaysCheckReturnValue(f) // old Options.qll
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class Options extends string
|
||||
fc.isInMacroExpansion()
|
||||
or
|
||||
// common way of sleeping using select:
|
||||
(fc.getTarget().hasQualifiedName("select") and
|
||||
(fc.getTarget().hasGlobalName("select") and
|
||||
fc.getArgument(0).getValue() = "0")
|
||||
or
|
||||
CustomOptions::okToIgnoreReturnValue(fc) // old Options.qll
|
||||
|
||||
@@ -58,11 +58,11 @@ predicate refToStdString(Expr e, ConstructorCall source) {
|
||||
* will also become invalid.
|
||||
*/
|
||||
predicate flowFunction(Function fcn, int argIndex) {
|
||||
(fcn.getQualifiedName() = "_JNIEnv::NewStringUTF" and argIndex = 0)
|
||||
(fcn.hasQualifiedName("", "_JNIEnv", "NewStringUTF") and argIndex = 0)
|
||||
or
|
||||
(fcn.getQualifiedName() = "art::JNI::NewStringUTF" and argIndex = 1)
|
||||
(fcn.hasQualifiedName("art", "JNI", "NewStringUTF") and argIndex = 1)
|
||||
or
|
||||
(fcn.getQualifiedName() = "art::CheckJNI::NewStringUTF" and argIndex = 1)
|
||||
(fcn.hasQualifiedName("art", "CheckJNI", "NewStringUTF") and argIndex = 1)
|
||||
|
||||
// Add other functions that behave like NewStringUTF here.
|
||||
}
|
||||
|
||||
@@ -13,13 +13,10 @@ import cpp
|
||||
|
||||
Expr getTest() {
|
||||
// cppunit tests; https://freedesktop.org/wiki/Software/cppunit/
|
||||
exists(Function f | result.(FunctionCall).getTarget() = f
|
||||
and f.getNamespace().getName() = "CppUnit"
|
||||
and f.getName() = "addTest")
|
||||
result.(FunctionCall).getTarget().hasQualifiedName("CppUnit", _, "addTest")
|
||||
or
|
||||
// boost tests; http://www.boost.org/
|
||||
exists(Function f | result.(FunctionCall).getTarget() = f
|
||||
and f.getQualifiedName() = "boost::unit_test::make_test_case")
|
||||
result.(FunctionCall).getTarget().hasQualifiedName("boost::unit_test", "make_test_case")
|
||||
}
|
||||
|
||||
from File f, int n
|
||||
|
||||
@@ -23,7 +23,7 @@ import semmle.code.cpp.security.TaintTracking
|
||||
*/
|
||||
class FileFunction extends FunctionWithWrappers {
|
||||
FileFunction() {
|
||||
exists(string nme | this.getQualifiedName() = nme |
|
||||
exists(string nme | this.hasGlobalName(nme) |
|
||||
nme = "fopen" or
|
||||
nme = "_fopen" or
|
||||
nme = "_wfopen" or
|
||||
@@ -32,10 +32,7 @@ class FileFunction extends FunctionWithWrappers {
|
||||
nme = "_wopen" or
|
||||
|
||||
// create file function on windows
|
||||
nme.matches("CreateFile%") or
|
||||
|
||||
// Objective C standard library
|
||||
nme.matches("NSFileHandle%::+fileHandleFor%AtPath:")
|
||||
nme.matches("CreateFile%")
|
||||
)
|
||||
or
|
||||
(
|
||||
|
||||
@@ -16,8 +16,8 @@ import semmle.code.cpp.security.TaintTracking
|
||||
/** A call that prints its arguments to `stdout`. */
|
||||
class PrintStdoutCall extends FunctionCall {
|
||||
PrintStdoutCall() {
|
||||
getTarget().hasQualifiedName("puts") or
|
||||
getTarget().hasQualifiedName("printf")
|
||||
getTarget().hasGlobalName("puts") or
|
||||
getTarget().hasGlobalName("printf")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,9 +73,9 @@ class VarargsFunction extends Function {
|
||||
}
|
||||
|
||||
predicate isWhitelisted() {
|
||||
this.hasQualifiedName("open") or
|
||||
this.hasQualifiedName("fcntl") or
|
||||
this.hasQualifiedName("ptrace")
|
||||
this.hasGlobalName("open") or
|
||||
this.hasGlobalName("fcntl") or
|
||||
this.hasGlobalName("ptrace")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ import cpp
|
||||
class MallocCall extends FunctionCall
|
||||
{
|
||||
MallocCall() {
|
||||
this.getTarget().hasQualifiedName("malloc") or
|
||||
this.getTarget().hasQualifiedName("std::malloc")
|
||||
this.getTarget().hasGlobalName("malloc") or
|
||||
this.getTarget().hasQualifiedName("std", "malloc")
|
||||
}
|
||||
|
||||
Expr getAllocatedSize() {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import cpp
|
||||
|
||||
predicate potentiallyDangerousFunction(Function f, string message) {
|
||||
exists(string name | name = f.getQualifiedName() |
|
||||
exists(string name | f.hasGlobalName(name) |
|
||||
(
|
||||
name = "gmtime" or
|
||||
name = "localtime" or
|
||||
@@ -21,7 +21,7 @@ predicate potentiallyDangerousFunction(Function f, string message) {
|
||||
) and
|
||||
message = "Call to " + name + " is potentially dangerous"
|
||||
) or (
|
||||
f.getQualifiedName() = "gets" and
|
||||
f.hasGlobalName("gets") and
|
||||
message = "gets does not guard against buffer overflow"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ predicate acquireExpr(Expr acquire, string kind) {
|
||||
exists(FunctionCall fc, Function f, string name |
|
||||
fc = acquire and
|
||||
f = fc.getTarget() and
|
||||
name = f.getQualifiedName() and
|
||||
f.hasGlobalName(name) and
|
||||
(
|
||||
(
|
||||
name = "fopen" and
|
||||
@@ -47,7 +47,7 @@ predicate releaseExpr(Expr release, Expr resource, string kind) {
|
||||
exists(FunctionCall fc, Function f, string name |
|
||||
fc = release and
|
||||
f = fc.getTarget() and
|
||||
name = f.getQualifiedName() and
|
||||
f.hasGlobalName(name) and
|
||||
(
|
||||
(
|
||||
name = "fclose" and
|
||||
@@ -252,7 +252,7 @@ pragma[noopt] predicate badRelease(Resource r, Expr acquire, Function functionCa
|
||||
)
|
||||
}
|
||||
|
||||
Class qtObject() { result.getABaseClass*().getQualifiedName() = "QObject" }
|
||||
Class qtObject() { result.getABaseClass*().hasGlobalName("QObject") }
|
||||
PointerType qtObjectReference() { result.getBaseType() = qtObject() }
|
||||
Constructor qtParentConstructor() {
|
||||
exists(Parameter p |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Specifier
|
||||
import semmle.code.cpp.Namespace
|
||||
private import semmle.code.cpp.internal.QualifiedName as Q
|
||||
|
||||
/**
|
||||
* A C/C++ declaration: for example, a variable declaration, a type
|
||||
@@ -30,16 +31,7 @@ abstract class Declaration extends Locatable, @declaration {
|
||||
* namespace of the structure.
|
||||
*/
|
||||
Namespace getNamespace() {
|
||||
// Top level declaration in a namespace ...
|
||||
result.getADeclaration() = this
|
||||
|
||||
// ... or nested in another structure.
|
||||
or
|
||||
exists (Declaration m
|
||||
| m = this and result = m.getDeclaringType().getNamespace())
|
||||
or
|
||||
exists (EnumConstant c
|
||||
| c = this and result = c.getDeclaringEnum().getNamespace())
|
||||
result = underlyingElement(this).(Q::Declaration).getNamespace()
|
||||
or
|
||||
exists (Parameter p
|
||||
| p = this and result = p.getFunction().getNamespace())
|
||||
@@ -50,40 +42,61 @@ abstract class Declaration extends Locatable, @declaration {
|
||||
|
||||
/**
|
||||
* Gets the name of the declaration, fully qualified with its
|
||||
* namespace. For example: "A::B::C::myfcn".
|
||||
* namespace and declaring type.
|
||||
*
|
||||
* For performance, prefer the multi-argument `hasQualifiedName` or
|
||||
* `hasGlobalName` predicates since they don't construct so many intermediate
|
||||
* strings. For debugging, the `semmle.code.cpp.Print` module produces more
|
||||
* detailed output but are also more expensive to compute.
|
||||
*
|
||||
* Example: `getQualifiedName() =
|
||||
* "namespace1::namespace2::TemplateClass1<int>::Class2::memberName"`.
|
||||
*/
|
||||
string getQualifiedName() {
|
||||
// MemberFunction, MemberVariable, MemberType
|
||||
exists (Declaration m
|
||||
| m = this and
|
||||
not m instanceof EnumConstant and
|
||||
result = m.getDeclaringType().getQualifiedName() + "::" + m.getName())
|
||||
or
|
||||
exists (EnumConstant c
|
||||
| c = this and
|
||||
result = c.getDeclaringEnum().getQualifiedName() + "::" + c.getName())
|
||||
or
|
||||
exists (GlobalOrNamespaceVariable v, string s1, string s2
|
||||
| v = this and
|
||||
s2 = v.getNamespace().getQualifiedName() and
|
||||
s1 = v.getName()
|
||||
| (s2 != "" and result = s2 + "::" + s1) or (s2 = "" and result = s1))
|
||||
or
|
||||
exists (Function f, string s1, string s2
|
||||
| f = this and f.isTopLevel() and
|
||||
s2 = f.getNamespace().getQualifiedName() and
|
||||
s1 = f.getName()
|
||||
| (s2 != "" and result = s2 + "::" + s1) or (s2 = "" and result = s1))
|
||||
or
|
||||
exists (UserType t, string s1, string s2
|
||||
| t = this and t.isTopLevel() and
|
||||
s2 = t.getNamespace().getQualifiedName() and
|
||||
s1 = t.getName()
|
||||
| (s2 != "" and result = s2 + "::" + s1) or (s2 = "" and result = s1))
|
||||
result = underlyingElement(this).(Q::Declaration).getQualifiedName()
|
||||
}
|
||||
|
||||
predicate hasQualifiedName(string name) {
|
||||
this.getQualifiedName() = name
|
||||
/**
|
||||
* DEPRECATED: Prefer `hasGlobalName` or the 2-argument or 3-argument
|
||||
* `hasQualifiedName` predicates. To get the exact same results as this
|
||||
* predicate in all edge cases, use `getQualifiedName()`.
|
||||
*
|
||||
* Holds if this declaration has the fully-qualified name `qualifiedName`.
|
||||
* See `getQualifiedName`.
|
||||
*/
|
||||
predicate hasQualifiedName(string qualifiedName) {
|
||||
this.getQualifiedName() = qualifiedName
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this declaration has a fully-qualified name with a name-space
|
||||
* component of `namespaceQualifier`, a declaring type of `typeQualifier`,
|
||||
* and a base name of `baseName`. Template parameters and arguments are
|
||||
* stripped from all components. Missing components are `""`.
|
||||
*
|
||||
* Example: `hasQualifiedName("namespace1::namespace2",
|
||||
* "TemplateClass1::Class2", "memberName")`.
|
||||
*
|
||||
* Example (the class `std::vector`): `hasQualifiedName("std", "", "vector")`
|
||||
* or `hasQualifiedName("std", "vector")`.
|
||||
*
|
||||
* Example (the `size` member function of class `std::vector`):
|
||||
* `hasQualifiedName("std", "vector", "size")`.
|
||||
*/
|
||||
predicate hasQualifiedName(string namespaceQualifier, string typeQualifier, string baseName) {
|
||||
underlyingElement(this).(Q::Declaration)
|
||||
.hasQualifiedName(namespaceQualifier, typeQualifier, baseName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this declaration has a fully-qualified name with a name-space
|
||||
* component of `namespaceQualifier`, no declaring type, and a base name of
|
||||
* `baseName`.
|
||||
*
|
||||
* See the 3-argument `hasQualifiedName` for examples.
|
||||
*/
|
||||
predicate hasQualifiedName(string namespaceQualifier, string baseName) {
|
||||
this.hasQualifiedName(namespaceQualifier, "", baseName)
|
||||
}
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
@@ -93,22 +106,24 @@ abstract class Declaration extends Locatable, @declaration {
|
||||
*
|
||||
* This name doesn't include a namespace or any argument types, so
|
||||
* for example both functions `::open()` and `::std::ifstream::open(...)`
|
||||
* have the same name.
|
||||
* have the same name. The name of a template _class_ includes a string
|
||||
* representation of its parameters, and the names of its instantiations
|
||||
* include string representations of their arguments. Template _functions_
|
||||
* and their instantiations do not include template parameters or arguments.
|
||||
*
|
||||
* To get the name including the namespace, use `getQualifiedName` or
|
||||
* `hasQualifiedName`.
|
||||
* To get the name including the namespace, use `hasQualifiedName`.
|
||||
*
|
||||
* To test whether this declaration has a particular name in the global
|
||||
* namespace, use `hasGlobalName`.
|
||||
*/
|
||||
abstract string getName();
|
||||
string getName() { result = underlyingElement(this).(Q::Declaration).getName() }
|
||||
|
||||
/** Holds if this declaration has the given name. */
|
||||
predicate hasName(string name) { name = this.getName() }
|
||||
|
||||
/** Holds if this declaration has the given name in the global namespace. */
|
||||
predicate hasGlobalName(string name) {
|
||||
hasName(name)
|
||||
and getNamespace() instanceof GlobalNamespace
|
||||
this.hasQualifiedName("", "", name)
|
||||
}
|
||||
|
||||
/** Gets a specifier of this declaration. */
|
||||
|
||||
@@ -100,11 +100,6 @@ class EnumConstant extends Declaration, @enumconstant {
|
||||
result = this.getDeclaringEnum().getDeclaringType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this enumerator.
|
||||
*/
|
||||
override string getName() { enumconstants(underlyingElement(this),_,_,_,result,_) }
|
||||
|
||||
/**
|
||||
* Gets the value that this enumerator is initialized to, as a
|
||||
* string. This can be a value explicitly given to the enumerator, or an
|
||||
|
||||
@@ -35,11 +35,6 @@ class FriendDecl extends Declaration, @frienddecl {
|
||||
/** Gets the location of this friend declaration. */
|
||||
override Location getLocation() { frienddecls(underlyingElement(this),_,_,result) }
|
||||
|
||||
/** Gets a descriptive string for this friend declaration. */
|
||||
override string getName() {
|
||||
result = this.getDeclaringClass().getName() + "'s friend"
|
||||
}
|
||||
|
||||
/**
|
||||
* Friend declarations do not have specifiers. It makes no difference
|
||||
* whether they are declared in a public, protected or private section of
|
||||
|
||||
@@ -17,8 +17,6 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* in more detail in `Declaration.qll`.
|
||||
*/
|
||||
class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
override string getName() { functions(underlyingElement(this),result,_) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
|
||||
* Gets the full signature of this function, including return type, parameter
|
||||
|
||||
@@ -148,9 +148,6 @@ deprecated class FinallyBlock extends Block {
|
||||
deprecated class Property extends Declaration {
|
||||
Property() { none() }
|
||||
|
||||
/** Gets the name of this property. */
|
||||
override string getName() { none() }
|
||||
|
||||
/**
|
||||
* Gets nothing (provided for compatibility with Declaration).
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Declaration
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
private import semmle.code.cpp.internal.QualifiedName as Q
|
||||
|
||||
/**
|
||||
* A C/C++ function parameter or catch block parameter.
|
||||
@@ -13,26 +14,6 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* have multiple declarations.
|
||||
*/
|
||||
class Parameter extends LocalScopeVariable, @parameter {
|
||||
|
||||
/**
|
||||
* Gets the canonical name, or names, of this parameter.
|
||||
*
|
||||
* The canonical names are the first non-empty category from the
|
||||
* following list:
|
||||
* 1. The name given to the parameter at the function's definition or
|
||||
* (for catch block parameters) at the catch block.
|
||||
* 2. A name given to the parameter at a function declaration.
|
||||
* 3. The name "p#i" where i is the index of the parameter.
|
||||
*/
|
||||
override string getName() {
|
||||
exists (VariableDeclarationEntry vde
|
||||
| vde = getANamedDeclarationEntry() and result = vde.getName()
|
||||
| vde.isDefinition() or not getANamedDeclarationEntry().isDefinition())
|
||||
or
|
||||
(not exists(getANamedDeclarationEntry()) and
|
||||
result = "p#" + this.getIndex().toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this parameter, including it's type.
|
||||
*
|
||||
@@ -53,27 +34,6 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
else result = typeString + nameString))
|
||||
}
|
||||
|
||||
private VariableDeclarationEntry getANamedDeclarationEntry() {
|
||||
result = getAnEffectiveDeclarationEntry() and result.getName() != ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a declaration entry corresponding to this declaration.
|
||||
*
|
||||
* This predicate is the same as getADeclarationEntry(), except that for
|
||||
* parameters of instantiated function templates, gives the declaration
|
||||
* entry of the prototype instantiation of the parameter (as
|
||||
* non-prototype instantiations don't have declaration entries of their
|
||||
* own).
|
||||
*/
|
||||
private VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
|
||||
if getFunction().isConstructedFrom(_)
|
||||
then exists (Function prototypeInstantiation
|
||||
| prototypeInstantiation.getParameter(getIndex()) = result.getVariable() and
|
||||
getFunction().isConstructedFrom(prototypeInstantiation))
|
||||
else result = getADeclarationEntry()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this parameter in the given block (which should be
|
||||
* the body of a function with which the parameter is associated).
|
||||
@@ -95,7 +55,9 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
* In other words, this predicate holds precisely when the result of
|
||||
* `getName()` is not "p#i" (where `i` is the index of the parameter).
|
||||
*/
|
||||
predicate isNamed() { exists(getANamedDeclarationEntry()) }
|
||||
predicate isNamed() {
|
||||
exists(underlyingElement(this).(Q::Parameter).getANamedDeclarationEntry())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function to which this parameter belongs, if it is a function
|
||||
@@ -135,8 +97,13 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
* of the declaration locations.
|
||||
*/
|
||||
override Location getLocation() {
|
||||
exists(VariableDeclarationEntry vde | vde = getAnEffectiveDeclarationEntry() and result = vde.getLocation() |
|
||||
vde.isDefinition() or not getAnEffectiveDeclarationEntry().isDefinition()
|
||||
exists(VariableDeclarationEntry vde |
|
||||
vde = underlyingElement(this).(Q::Parameter).getAnEffectiveDeclarationEntry() and
|
||||
result = vde.getLocation()
|
||||
|
|
||||
vde.isDefinition()
|
||||
or
|
||||
not underlyingElement(this).(Q::Parameter).getAnEffectiveDeclarationEntry().isDefinition()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ private abstract class DumpDeclaration extends Declaration {
|
||||
* Gets a string that uniquely identifies this declaration, suitable for use when debugging queries. Only holds for
|
||||
* functions, user-defined types, global and namespace-scope variables, and member variables.
|
||||
*
|
||||
* This operation is very expensive, and should not be used in production queries. Consider using `hasName()` or
|
||||
* This operation is very expensive, and should not be used in production queries. Consider using
|
||||
* `hasQualifiedName()` for identifying known declarations in production queries.
|
||||
*/
|
||||
string getIdentityString() {
|
||||
|
||||
@@ -9,10 +9,9 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* `Enum`, and `TypedefType`.
|
||||
*/
|
||||
class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @usertype {
|
||||
/**
|
||||
* Gets the name of this type.
|
||||
*/
|
||||
override string getName() { usertypes(underlyingElement(this),result,_) }
|
||||
override string getName() {
|
||||
result = Declaration.super.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the simple name of this type, without any template parameters. For example
|
||||
|
||||
@@ -41,9 +41,6 @@ class Variable extends Declaration, @variable {
|
||||
/** Holds if this variable is `volatile`. */
|
||||
predicate isVolatile() { this.getType().isVolatile() }
|
||||
|
||||
/** Gets the name of this variable. */
|
||||
override string getName() { none() }
|
||||
|
||||
/** Gets the type of this variable. */
|
||||
Type getType() { none() }
|
||||
|
||||
@@ -291,8 +288,6 @@ deprecated class StackVariable extends Variable {
|
||||
* A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`.
|
||||
*/
|
||||
class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
override string getName() { localvariables(underlyingElement(this),_,result) }
|
||||
|
||||
override Type getType() { localvariables(underlyingElement(this),unresolveElement(result),_) }
|
||||
|
||||
override Function getFunction() {
|
||||
@@ -305,8 +300,6 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
* A C/C++ variable which has global scope or namespace scope.
|
||||
*/
|
||||
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
|
||||
override string getName() { globalvariables(underlyingElement(this),_,result) }
|
||||
|
||||
override Type getType() { globalvariables(underlyingElement(this),unresolveElement(result),_) }
|
||||
|
||||
override Element getEnclosingElement() { none() }
|
||||
@@ -354,8 +347,6 @@ class MemberVariable extends Variable, @membervariable {
|
||||
/** Holds if this member is public. */
|
||||
predicate isPublic() { this.hasSpecifier("public") }
|
||||
|
||||
override string getName() { membervariables(underlyingElement(this),_,result) }
|
||||
|
||||
override Type getType() {
|
||||
if (strictcount(this.getAType()) = 1) then (
|
||||
result = this.getAType()
|
||||
|
||||
@@ -6,7 +6,7 @@ import cpp
|
||||
predicate allocationFunction(Function f)
|
||||
{
|
||||
exists(string name |
|
||||
f.hasQualifiedName(name) and
|
||||
f.hasGlobalName(name) and
|
||||
(
|
||||
name = "malloc" or
|
||||
name = "calloc" or
|
||||
@@ -61,7 +61,7 @@ predicate allocationCall(FunctionCall fc)
|
||||
allocationFunction(fc.getTarget()) and
|
||||
(
|
||||
// realloc(ptr, 0) only frees the pointer
|
||||
fc.getTarget().hasQualifiedName("realloc") implies
|
||||
fc.getTarget().hasGlobalName("realloc") implies
|
||||
not fc.getArgument(1).getValue() = "0"
|
||||
)
|
||||
}
|
||||
@@ -72,7 +72,7 @@ predicate allocationCall(FunctionCall fc)
|
||||
predicate freeFunction(Function f, int argNum)
|
||||
{
|
||||
exists(string name |
|
||||
f.hasQualifiedName(name) and
|
||||
f.hasGlobalName(name) and
|
||||
(
|
||||
(name = "free" and argNum = 0) or
|
||||
(name = "realloc" and argNum = 0) or
|
||||
|
||||
@@ -6,16 +6,16 @@ import cpp
|
||||
predicate fopenCall(FunctionCall fc)
|
||||
{
|
||||
exists(Function f | f = fc.getTarget() |
|
||||
f.hasQualifiedName("fopen") or
|
||||
f.hasQualifiedName("open") or
|
||||
f.hasQualifiedName("_open") or
|
||||
f.hasQualifiedName("_wopen") or
|
||||
f.hasQualifiedName("CreateFile") or
|
||||
f.hasQualifiedName("CreateFileA") or
|
||||
f.hasQualifiedName("CreateFileW") or
|
||||
f.hasQualifiedName("CreateFileTransacted") or
|
||||
f.hasQualifiedName("CreateFileTransactedA") or
|
||||
f.hasQualifiedName("CreateFileTransactedW")
|
||||
f.hasGlobalName("fopen") or
|
||||
f.hasGlobalName("open") or
|
||||
f.hasGlobalName("_open") or
|
||||
f.hasGlobalName("_wopen") or
|
||||
f.hasGlobalName("CreateFile") or
|
||||
f.hasGlobalName("CreateFileA") or
|
||||
f.hasGlobalName("CreateFileW") or
|
||||
f.hasGlobalName("CreateFileTransacted") or
|
||||
f.hasGlobalName("CreateFileTransactedA") or
|
||||
f.hasGlobalName("CreateFileTransactedW")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,16 +26,16 @@ predicate fcloseCall(FunctionCall fc, Expr closed)
|
||||
{
|
||||
exists(Function f | f = fc.getTarget() |
|
||||
(
|
||||
f.hasQualifiedName("fclose") and
|
||||
f.hasGlobalName("fclose") and
|
||||
closed = fc.getArgument(0)
|
||||
) or (
|
||||
f.hasQualifiedName("close") and
|
||||
f.hasGlobalName("close") and
|
||||
closed = fc.getArgument(0)
|
||||
) or (
|
||||
f.hasQualifiedName("_close") and
|
||||
f.hasGlobalName("_close") and
|
||||
closed = fc.getArgument(0)
|
||||
) or (
|
||||
f.hasQualifiedName("CloseHandle") and
|
||||
f.hasGlobalName("CloseHandle") and
|
||||
closed = fc.getArgument(0)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -74,20 +74,6 @@ class UserDefinedFormattingFunction extends FormattingFunction {
|
||||
override int getFormatParameterIndex() { callsVariadicFormatter(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The Objective C method `stringWithFormat:`.
|
||||
*/
|
||||
class NsstringStringWithFormat extends FormattingFunction {
|
||||
NsstringStringWithFormat() {
|
||||
getQualifiedName().matches("NSString%::+stringWithFormat:") or
|
||||
getQualifiedName().matches("NSString%::+localizedStringWithFormat:")
|
||||
}
|
||||
|
||||
override int getFormatParameterIndex() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to one of the formatting functions.
|
||||
*/
|
||||
|
||||
@@ -56,12 +56,12 @@ class AnalysedString extends Expr
|
||||
*/
|
||||
class StrlenCall extends FunctionCall {
|
||||
StrlenCall() {
|
||||
this.getTarget().hasQualifiedName("strlen") or
|
||||
this.getTarget().hasQualifiedName("wcslen") or
|
||||
this.getTarget().hasQualifiedName("_mbslen") or
|
||||
this.getTarget().hasQualifiedName("_mbslen_l") or
|
||||
this.getTarget().hasQualifiedName("_mbstrlen") or
|
||||
this.getTarget().hasQualifiedName("_mbstrlen_l")
|
||||
this.getTarget().hasGlobalName("strlen") or
|
||||
this.getTarget().hasGlobalName("wcslen") or
|
||||
this.getTarget().hasGlobalName("_mbslen") or
|
||||
this.getTarget().hasGlobalName("_mbslen_l") or
|
||||
this.getTarget().hasGlobalName("_mbstrlen") or
|
||||
this.getTarget().hasGlobalName("_mbstrlen_l")
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ import Nullness
|
||||
predicate callDereferences(FunctionCall fc, int i)
|
||||
{
|
||||
exists(string name |
|
||||
fc.getTarget().hasQualifiedName(name) and
|
||||
fc.getTarget().hasGlobalName(name) and
|
||||
(
|
||||
(name = "bcopy" and i in [0..1]) or
|
||||
(name = "memcpy" and i in [0..1]) or
|
||||
|
||||
@@ -47,7 +47,7 @@ predicate nullCheckExpr(Expr checkExpr, Variable var)
|
||||
or
|
||||
exists(FunctionCall fc, AnalysedExpr child |
|
||||
expr = fc and
|
||||
fc.getTarget().hasQualifiedName("__builtin_expect") and
|
||||
fc.getTarget().hasGlobalName("__builtin_expect") and
|
||||
fc.getArgument(0) = child and nullCheckExpr(child, v))
|
||||
)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ predicate validCheckExpr(Expr checkExpr, Variable var)
|
||||
or
|
||||
exists(FunctionCall fc, AnalysedExpr child |
|
||||
expr = fc and
|
||||
fc.getTarget().hasQualifiedName("__builtin_expect") and
|
||||
fc.getTarget().hasGlobalName("__builtin_expect") and
|
||||
fc.getArgument(0) = child and validCheckExpr(child, v))
|
||||
)
|
||||
}
|
||||
@@ -260,13 +260,13 @@ predicate callMayReturnNull(Call call)
|
||||
*/
|
||||
predicate mayReturnNull(Function f)
|
||||
{
|
||||
f.getQualifiedName() = "malloc"
|
||||
f.hasGlobalName("malloc")
|
||||
or
|
||||
f.getQualifiedName() = "calloc"
|
||||
f.hasGlobalName("calloc")
|
||||
or
|
||||
// f.getQualifiedName() = "strchr"
|
||||
// f.hasGlobalName("strchr")
|
||||
// or
|
||||
// f.getQualifiedName() = "strstr"
|
||||
// f.hasGlobalName("strstr")
|
||||
// or
|
||||
exists(ReturnStmt ret |
|
||||
nullValue(ret.getExpr()) and
|
||||
|
||||
353
cpp/ql/src/semmle/code/cpp/internal/QualifiedName.qll
Normal file
353
cpp/ql/src/semmle/code/cpp/internal/QualifiedName.qll
Normal file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* INTERNAL: Do not use. Provides classes and predicates for getting names of
|
||||
* declarations, especially qualified names. Import this library `private` and
|
||||
* qualified.
|
||||
*
|
||||
* This file contains classes that mirror the standard AST classes for C++, but
|
||||
* these classes are only concerned with naming. The other difference is that
|
||||
* these classes don't use the `ResolveClass.qll` mechanisms like
|
||||
* `unresolveElement` because these classes should eventually be part of the
|
||||
* implementation of `ResolveClass.qll`, allowing it to match up classes when
|
||||
* their qualified names and parameters match.
|
||||
*/
|
||||
|
||||
class Namespace extends @namespace {
|
||||
string toString() { result = "QualifiedName Namespace" }
|
||||
|
||||
string getName() { namespaces(this, result) }
|
||||
|
||||
string getQualifiedName() {
|
||||
if namespacembrs(_, this)
|
||||
then
|
||||
exists(Namespace ns |
|
||||
namespacembrs(ns, this) and
|
||||
result = ns.getQualifiedName() + "::" + this.getName()
|
||||
)
|
||||
else result = this.getName()
|
||||
}
|
||||
|
||||
Declaration getADeclaration() {
|
||||
if this.getName() = ""
|
||||
then result.isTopLevel() and not namespacembrs(_, result)
|
||||
else namespacembrs(this, result)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Declaration extends @declaration {
|
||||
string toString() { result = "QualifiedName Declaration" }
|
||||
|
||||
/** Gets the name of this declaration. */
|
||||
cached
|
||||
abstract string getName();
|
||||
|
||||
string getTypeQualifierWithoutArgs() {
|
||||
exists(UserType declaringType |
|
||||
declaringType = this.(EnumConstant).getDeclaringEnum()
|
||||
or
|
||||
declaringType = this.getDeclaringType()
|
||||
|
|
||||
result = getTypeQualifierForMembersWithoutArgs(declaringType)
|
||||
)
|
||||
}
|
||||
|
||||
string getTypeQualifierWithArgs() {
|
||||
exists(UserType declaringType |
|
||||
declaringType = this.(EnumConstant).getDeclaringEnum()
|
||||
or
|
||||
declaringType = this.getDeclaringType()
|
||||
|
|
||||
result = getTypeQualifierForMembersWithArgs(declaringType)
|
||||
)
|
||||
}
|
||||
|
||||
Namespace getNamespace() {
|
||||
// Top level declaration in a namespace ...
|
||||
result.getADeclaration() = this
|
||||
or
|
||||
// ... or nested in another structure.
|
||||
exists(Declaration m | m = this and result = m.getDeclaringType().getNamespace())
|
||||
or
|
||||
exists(EnumConstant c | c = this and result = c.getDeclaringEnum().getNamespace())
|
||||
}
|
||||
|
||||
predicate hasQualifiedName(string namespaceQualifier, string typeQualifier, string baseName) {
|
||||
declarationHasQualifiedName(baseName, typeQualifier, namespaceQualifier, this)
|
||||
}
|
||||
|
||||
string getQualifiedName() {
|
||||
exists(string ns, string name |
|
||||
ns = this.getNamespace().getQualifiedName() and
|
||||
name = this.getName() and
|
||||
this.canHaveQualifiedName()
|
||||
|
|
||||
exists(string t | t = this.getTypeQualifierWithArgs() |
|
||||
if ns != ""
|
||||
then result = ns + "::" + t + "::" + name
|
||||
else result = t + "::" + name
|
||||
)
|
||||
or
|
||||
not hasTypeQualifier(this) and
|
||||
if ns != ""
|
||||
then result = ns + "::" + name
|
||||
else result = name
|
||||
)
|
||||
}
|
||||
|
||||
predicate canHaveQualifiedName() {
|
||||
this.hasDeclaringType()
|
||||
or
|
||||
this instanceof EnumConstant
|
||||
or
|
||||
this instanceof Function
|
||||
or
|
||||
this instanceof UserType
|
||||
or
|
||||
this instanceof GlobalOrNamespaceVariable
|
||||
}
|
||||
|
||||
predicate isTopLevel() {
|
||||
not (
|
||||
this.isMember() or
|
||||
this instanceof FriendDecl or
|
||||
this instanceof EnumConstant or
|
||||
this instanceof Parameter or
|
||||
this instanceof ProxyClass or
|
||||
this instanceof LocalVariable or
|
||||
this instanceof TemplateParameter or
|
||||
this.(UserType).isLocal()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this declaration is a member of a class/struct/union. */
|
||||
predicate isMember() { this.hasDeclaringType() }
|
||||
|
||||
/** Holds if this declaration is a member of a class/struct/union. */
|
||||
predicate hasDeclaringType() { exists(this.getDeclaringType()) }
|
||||
|
||||
/**
|
||||
* Gets the class where this member is declared, if it is a member.
|
||||
* For templates, both the template itself and all instantiations of
|
||||
* the template are considered to have the same declaring class.
|
||||
*/
|
||||
UserType getDeclaringType() { this = result.getAMember() }
|
||||
}
|
||||
|
||||
class Variable extends Declaration, @variable {
|
||||
override string getName() { none() }
|
||||
|
||||
VariableDeclarationEntry getADeclarationEntry() { result.getDeclaration() = this }
|
||||
}
|
||||
|
||||
class TemplateVariable extends Variable {
|
||||
TemplateVariable() { is_variable_template(this) }
|
||||
|
||||
Variable getAnInstantiation() { variable_instantiation(result, this) }
|
||||
}
|
||||
|
||||
class LocalScopeVariable extends Variable, @localscopevariable { }
|
||||
|
||||
class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
override string getName() { localvariables(this, _, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A particular declaration or definition of a C/C++ variable.
|
||||
*/
|
||||
class VariableDeclarationEntry extends @var_decl {
|
||||
string toString() { result = "QualifiedName DeclarationEntry" }
|
||||
|
||||
Variable getDeclaration() { result = getVariable() }
|
||||
|
||||
/**
|
||||
* Gets the variable which is being declared or defined.
|
||||
*/
|
||||
Variable getVariable() { var_decls(this, result, _, _, _) }
|
||||
|
||||
predicate isDefinition() { var_def(this) }
|
||||
|
||||
string getName() { var_decls(this, _, _, result, _) and result != "" }
|
||||
}
|
||||
|
||||
class Parameter extends LocalScopeVariable, @parameter {
|
||||
@functionorblock function;
|
||||
|
||||
int index;
|
||||
|
||||
Parameter() { params(this, function, index, _) }
|
||||
|
||||
/**
|
||||
* Gets the canonical name, or names, of this parameter.
|
||||
*
|
||||
* The canonical names are the first non-empty category from the
|
||||
* following list:
|
||||
* 1. The name given to the parameter at the function's definition or
|
||||
* (for catch block parameters) at the catch block.
|
||||
* 2. A name given to the parameter at a function declaration.
|
||||
* 3. The name "p#i" where i is the index of the parameter.
|
||||
*/
|
||||
override string getName() {
|
||||
exists(VariableDeclarationEntry vde |
|
||||
vde = getANamedDeclarationEntry() and result = vde.getName()
|
||||
|
|
||||
vde.isDefinition() or not getANamedDeclarationEntry().isDefinition()
|
||||
)
|
||||
or
|
||||
not exists(getANamedDeclarationEntry()) and
|
||||
result = "p#" + index.toString()
|
||||
}
|
||||
|
||||
VariableDeclarationEntry getANamedDeclarationEntry() {
|
||||
result = getAnEffectiveDeclarationEntry() and exists(result.getName())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a declaration entry corresponding to this declaration.
|
||||
*
|
||||
* This predicate is the same as getADeclarationEntry(), except that for
|
||||
* parameters of instantiated function templates, gives the declaration
|
||||
* entry of the prototype instantiation of the parameter (as
|
||||
* non-prototype instantiations don't have declaration entries of their
|
||||
* own).
|
||||
*/
|
||||
VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
|
||||
if function.(Function).isConstructedFrom(_)
|
||||
then
|
||||
exists(Function prototypeInstantiation |
|
||||
prototypeInstantiation.getParameter(index) = result.getVariable() and
|
||||
function.(Function).isConstructedFrom(prototypeInstantiation)
|
||||
)
|
||||
else result = getADeclarationEntry()
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
|
||||
override string getName() { globalvariables(this, _, result) }
|
||||
}
|
||||
|
||||
class MemberVariable extends Variable, @membervariable {
|
||||
MemberVariable() { this.isMember() }
|
||||
|
||||
override string getName() { membervariables(this, _, result) }
|
||||
}
|
||||
|
||||
// Unlike the usual `EnumConstant`, this one doesn't have a
|
||||
// `getDeclaringType()`. This simplifies the recursive computation of type
|
||||
// qualifier names since it can assume that any declaration with a
|
||||
// `getDeclaringType()` should use that type in its type qualifier name.
|
||||
class EnumConstant extends Declaration, @enumconstant {
|
||||
override string getName() { enumconstants(this, _, _, _, result, _) }
|
||||
|
||||
UserType getDeclaringEnum() { enumconstants(this, result, _, _, _, _) }
|
||||
}
|
||||
|
||||
class Function extends Declaration, @function {
|
||||
override string getName() { functions(this, result, _) }
|
||||
|
||||
predicate isConstructedFrom(Function f) { function_instantiation(this, f) }
|
||||
|
||||
Parameter getParameter(int n) { params(result, this, n, _) }
|
||||
}
|
||||
|
||||
class TemplateFunction extends Function {
|
||||
TemplateFunction() { is_function_template(this) and function_template_argument(this, _, _) }
|
||||
|
||||
Function getAnInstantiation() {
|
||||
function_instantiation(result, this) and
|
||||
not exists(@fun_decl fd | fun_decls(fd, this, _, _, _) and fun_specialized(fd))
|
||||
}
|
||||
}
|
||||
|
||||
class UserType extends Declaration, @usertype {
|
||||
override string getName() { result = getUserTypeNameWithArgs(this) }
|
||||
|
||||
predicate isLocal() { enclosingfunction(this, _) }
|
||||
|
||||
// Gets a member of this class, if it's a class.
|
||||
Declaration getAMember() {
|
||||
exists(Declaration d | member(this, _, d) |
|
||||
result = d or
|
||||
result = d.(TemplateClass).getAnInstantiation() or
|
||||
result = d.(TemplateFunction).getAnInstantiation() or
|
||||
result = d.(TemplateVariable).getAnInstantiation()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyClass extends UserType {
|
||||
ProxyClass() { usertypes(this, _, 9) }
|
||||
}
|
||||
|
||||
class TemplateParameter extends UserType {
|
||||
TemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) }
|
||||
}
|
||||
|
||||
class TemplateClass extends UserType {
|
||||
TemplateClass() { usertypes(this, _, 6) }
|
||||
|
||||
UserType getAnInstantiation() {
|
||||
class_instantiation(result, this) and
|
||||
class_template_argument(result, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
class FriendDecl extends Declaration, @frienddecl {
|
||||
override string getName() {
|
||||
result = getUserTypeNameWithArgs(this.getDeclaringClass()) + "'s friend"
|
||||
}
|
||||
|
||||
UserType getDeclaringClass() { frienddecls(this, result, _, _) }
|
||||
}
|
||||
|
||||
private string getUserTypeNameWithArgs(UserType t) { usertypes(t, result, _) }
|
||||
|
||||
private string getUserTypeNameWithoutArgs(UserType t) {
|
||||
result = getUserTypeNameWithArgs(t).splitAt("<", 0)
|
||||
}
|
||||
|
||||
private predicate hasTypeQualifier(Declaration d) {
|
||||
d instanceof EnumConstant
|
||||
or
|
||||
d.hasDeclaringType()
|
||||
}
|
||||
|
||||
private string getTypeQualifierForMembersWithArgs(UserType t) {
|
||||
result = t.getTypeQualifierWithArgs() + "::" + getUserTypeNameWithArgs(t)
|
||||
or
|
||||
not hasTypeQualifier(t) and
|
||||
result = getUserTypeNameWithArgs(t)
|
||||
}
|
||||
|
||||
private string getTypeQualifierForMembersWithoutArgs(UserType t) {
|
||||
result = t.getTypeQualifierWithoutArgs() + "::" + getUserTypeNameWithoutArgs(t)
|
||||
or
|
||||
not hasTypeQualifier(t) and
|
||||
result = getUserTypeNameWithoutArgs(t)
|
||||
}
|
||||
|
||||
// The order of parameters on this predicate is chosen to match the most common
|
||||
// use case: finding a declaration that has a specific name. The declaration
|
||||
// comes last because it's the output.
|
||||
cached
|
||||
private predicate declarationHasQualifiedName(
|
||||
string baseName, string typeQualifier, string namespaceQualifier, Declaration d
|
||||
) {
|
||||
namespaceQualifier = d.getNamespace().getQualifiedName() and
|
||||
(
|
||||
if hasTypeQualifier(d)
|
||||
then typeQualifier = d.getTypeQualifierWithoutArgs()
|
||||
else typeQualifier = ""
|
||||
) and
|
||||
(
|
||||
baseName = getUserTypeNameWithoutArgs(d)
|
||||
or
|
||||
// If a declaration isn't a `UserType`, there are two ways it can still
|
||||
// contain `<`:
|
||||
// 1. If it's `operator<` or `operator<<`.
|
||||
// 2. If it's a conversion operator like `operator TemplateClass<Arg>`.
|
||||
// Perhaps these names ought to be fixed up, but we don't do that
|
||||
// currently.
|
||||
not d instanceof UserType and
|
||||
baseName = d.getName()
|
||||
) and
|
||||
d.canHaveQualifiedName()
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
|
||||
class InetNtoa extends TaintFunction {
|
||||
InetNtoa() {
|
||||
hasQualifiedName("inet_ntoa")
|
||||
hasGlobalName("inet_ntoa")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -14,7 +14,7 @@ class InetNtoa extends TaintFunction {
|
||||
|
||||
class InetAton extends TaintFunction, ArrayFunction {
|
||||
InetAton() {
|
||||
hasQualifiedName("inet_aton")
|
||||
hasGlobalName("inet_aton")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -42,7 +42,7 @@ class InetAton extends TaintFunction, ArrayFunction {
|
||||
|
||||
class InetAddr extends TaintFunction, ArrayFunction {
|
||||
InetAddr() {
|
||||
hasQualifiedName("inet_addr")
|
||||
hasGlobalName("inet_addr")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -61,7 +61,7 @@ class InetAddr extends TaintFunction, ArrayFunction {
|
||||
|
||||
class InetNetwork extends TaintFunction, ArrayFunction {
|
||||
InetNetwork() {
|
||||
hasQualifiedName("inet_network")
|
||||
hasGlobalName("inet_network")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -80,7 +80,7 @@ class InetNetwork extends TaintFunction, ArrayFunction {
|
||||
|
||||
class InetMakeaddr extends TaintFunction {
|
||||
InetMakeaddr() {
|
||||
hasQualifiedName("inet_makeaddr")
|
||||
hasGlobalName("inet_makeaddr")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -94,7 +94,7 @@ class InetMakeaddr extends TaintFunction {
|
||||
|
||||
class InetLnaof extends TaintFunction {
|
||||
InetLnaof() {
|
||||
hasQualifiedName("inet_lnaof")
|
||||
hasGlobalName("inet_lnaof")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -105,7 +105,7 @@ class InetLnaof extends TaintFunction {
|
||||
|
||||
class InetNetof extends TaintFunction {
|
||||
InetNetof() {
|
||||
hasQualifiedName("inet_netof")
|
||||
hasGlobalName("inet_netof")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -116,7 +116,7 @@ class InetNetof extends TaintFunction {
|
||||
|
||||
class InetPton extends TaintFunction, ArrayFunction {
|
||||
InetPton() {
|
||||
hasQualifiedName("inet_pton")
|
||||
hasGlobalName("inet_pton")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -146,7 +146,7 @@ class InetPton extends TaintFunction, ArrayFunction {
|
||||
|
||||
class Gethostbyname extends TaintFunction, ArrayFunction {
|
||||
Gethostbyname() {
|
||||
hasQualifiedName("gethostbyname")
|
||||
hasGlobalName("gethostbyname")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -165,7 +165,7 @@ class Gethostbyname extends TaintFunction, ArrayFunction {
|
||||
|
||||
class Gethostbyaddr extends TaintFunction, ArrayFunction {
|
||||
Gethostbyaddr() {
|
||||
hasQualifiedName("gethostbyaddr")
|
||||
hasGlobalName("gethostbyaddr")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
|
||||
@@ -69,8 +69,8 @@ class Sprintf extends FormattingFunction {
|
||||
or
|
||||
hasGlobalName("__builtin___sprintf_chk") and result = 3
|
||||
or
|
||||
getQualifiedName() != "g_strdup_printf" and
|
||||
getQualifiedName() != "__builtin___sprintf_chk" and
|
||||
getName() != "g_strdup_printf" and
|
||||
getName() != "__builtin___sprintf_chk" and
|
||||
result = 1
|
||||
}
|
||||
override int getOutputParameterIndex() {
|
||||
@@ -127,7 +127,7 @@ class Snprintf extends FormattingFunction {
|
||||
|
||||
override int getFirstFormatArgumentIndex() {
|
||||
exists(string name |
|
||||
name = getQualifiedName()
|
||||
hasGlobalName(name)
|
||||
and (
|
||||
name = "__builtin___snprintf_chk" and
|
||||
result = 5
|
||||
|
||||
@@ -3,7 +3,7 @@ import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
|
||||
class Strftime extends TaintFunction, ArrayFunction {
|
||||
Strftime() {
|
||||
hasQualifiedName("strftime")
|
||||
hasGlobalName("strftime")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
|
||||
@@ -588,7 +588,7 @@ predicate allocateDescriptorCall(FunctionCall fc)
|
||||
{
|
||||
exists(string name |
|
||||
name = "socket" and
|
||||
fc.getTarget().hasQualifiedName(name))
|
||||
fc.getTarget().hasGlobalName(name))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -532,7 +532,7 @@ private int path_max() {
|
||||
class RealpathBW extends BufferWriteCall {
|
||||
RealpathBW() {
|
||||
exists(path_max()) and // Ignore realpath() calls if PATH_MAX cannot be determined
|
||||
getTarget().getQualifiedName() = "realpath" // realpath(path, resolved_path);
|
||||
getTarget().hasGlobalName("realpath") // realpath(path, resolved_path);
|
||||
}
|
||||
|
||||
override Type getBufferType()
|
||||
|
||||
@@ -9,13 +9,13 @@ import semmle.code.cpp.security.FunctionWithWrappers
|
||||
*/
|
||||
class SystemFunction extends FunctionWithWrappers {
|
||||
SystemFunction() {
|
||||
hasQualifiedName("system")
|
||||
or hasQualifiedName("popen")
|
||||
hasGlobalName("system")
|
||||
or hasGlobalName("popen")
|
||||
|
||||
// Windows variants
|
||||
or hasQualifiedName("_popen")
|
||||
or hasQualifiedName("_wpopen")
|
||||
or hasQualifiedName("_wsystem")
|
||||
or hasGlobalName("_popen")
|
||||
or hasGlobalName("_wpopen")
|
||||
or hasGlobalName("_wsystem")
|
||||
}
|
||||
|
||||
override predicate interestingArg(int arg) {
|
||||
@@ -31,36 +31,36 @@ class SystemFunction extends FunctionWithWrappers {
|
||||
*/
|
||||
class VarargsExecFunctionCall extends FunctionCall {
|
||||
VarargsExecFunctionCall() {
|
||||
getTarget().hasQualifiedName("execl")
|
||||
or getTarget().hasQualifiedName("execle")
|
||||
or getTarget().hasQualifiedName("execlp")
|
||||
getTarget().hasGlobalName("execl")
|
||||
or getTarget().hasGlobalName("execle")
|
||||
or getTarget().hasGlobalName("execlp")
|
||||
|
||||
// Windows
|
||||
or getTarget().hasQualifiedName("_execl")
|
||||
or getTarget().hasQualifiedName("_execle")
|
||||
or getTarget().hasQualifiedName("_execlp")
|
||||
or getTarget().hasQualifiedName("_execlpe")
|
||||
or getTarget().hasQualifiedName("_spawnl")
|
||||
or getTarget().hasQualifiedName("_spawnle")
|
||||
or getTarget().hasQualifiedName("_spawnlp")
|
||||
or getTarget().hasQualifiedName("_spawnlpe")
|
||||
or getTarget().hasQualifiedName("_wexecl")
|
||||
or getTarget().hasQualifiedName("_wexecle")
|
||||
or getTarget().hasQualifiedName("_wexeclp")
|
||||
or getTarget().hasQualifiedName("_wexeclpe")
|
||||
or getTarget().hasQualifiedName("_wspawnl")
|
||||
or getTarget().hasQualifiedName("_wspawnle")
|
||||
or getTarget().hasQualifiedName("_wspawnlp")
|
||||
or getTarget().hasQualifiedName("_wspawnlpe")
|
||||
or getTarget().hasGlobalName("_execl")
|
||||
or getTarget().hasGlobalName("_execle")
|
||||
or getTarget().hasGlobalName("_execlp")
|
||||
or getTarget().hasGlobalName("_execlpe")
|
||||
or getTarget().hasGlobalName("_spawnl")
|
||||
or getTarget().hasGlobalName("_spawnle")
|
||||
or getTarget().hasGlobalName("_spawnlp")
|
||||
or getTarget().hasGlobalName("_spawnlpe")
|
||||
or getTarget().hasGlobalName("_wexecl")
|
||||
or getTarget().hasGlobalName("_wexecle")
|
||||
or getTarget().hasGlobalName("_wexeclp")
|
||||
or getTarget().hasGlobalName("_wexeclpe")
|
||||
or getTarget().hasGlobalName("_wspawnl")
|
||||
or getTarget().hasGlobalName("_wspawnle")
|
||||
or getTarget().hasGlobalName("_wspawnlp")
|
||||
or getTarget().hasGlobalName("_wspawnlpe")
|
||||
}
|
||||
|
||||
/** Whether the last argument to the function is an environment pointer */
|
||||
predicate hasEnvironmentArgument() {
|
||||
getTarget().hasQualifiedName("execle")
|
||||
or getTarget().hasQualifiedName("_execle")
|
||||
or getTarget().hasQualifiedName("_execlpe")
|
||||
or getTarget().hasQualifiedName("_wexecle")
|
||||
or getTarget().hasQualifiedName("_wexeclpe")
|
||||
getTarget().hasGlobalName("execle")
|
||||
or getTarget().hasGlobalName("_execle")
|
||||
or getTarget().hasGlobalName("_execlpe")
|
||||
or getTarget().hasGlobalName("_wexecle")
|
||||
or getTarget().hasGlobalName("_wexeclpe")
|
||||
}
|
||||
|
||||
/** The arguments passed to the command. The 0th such argument is conventionally
|
||||
@@ -85,8 +85,8 @@ class VarargsExecFunctionCall extends FunctionCall {
|
||||
* all the other ones start with the command. */
|
||||
private int getCommandIdx() {
|
||||
if (
|
||||
getTarget().getQualifiedName().matches("\\_spawn%")
|
||||
or getTarget().getQualifiedName().matches("\\_wspawn%"))
|
||||
getTarget().getName().matches("\\_spawn%")
|
||||
or getTarget().getName().matches("\\_wspawn%"))
|
||||
then result = 1
|
||||
else result = 0
|
||||
}
|
||||
@@ -100,27 +100,27 @@ class VarargsExecFunctionCall extends FunctionCall {
|
||||
*/
|
||||
class ArrayExecFunctionCall extends FunctionCall {
|
||||
ArrayExecFunctionCall() {
|
||||
getTarget().hasQualifiedName("execv")
|
||||
or getTarget().hasQualifiedName("execvp")
|
||||
or getTarget().hasQualifiedName("execvpe")
|
||||
getTarget().hasGlobalName("execv")
|
||||
or getTarget().hasGlobalName("execvp")
|
||||
or getTarget().hasGlobalName("execvpe")
|
||||
|
||||
// Windows variants
|
||||
or getTarget().hasQualifiedName("_execv")
|
||||
or getTarget().hasQualifiedName("_execve")
|
||||
or getTarget().hasQualifiedName("_execvp")
|
||||
or getTarget().hasQualifiedName("_execvpe")
|
||||
or getTarget().hasQualifiedName("_spawnv")
|
||||
or getTarget().hasQualifiedName("_spawnve")
|
||||
or getTarget().hasQualifiedName("_spawnvp")
|
||||
or getTarget().hasQualifiedName("_spawnvpe")
|
||||
or getTarget().hasQualifiedName("_wexecv")
|
||||
or getTarget().hasQualifiedName("_wexecve")
|
||||
or getTarget().hasQualifiedName("_wexecvp")
|
||||
or getTarget().hasQualifiedName("_wexecvpe")
|
||||
or getTarget().hasQualifiedName("_wspawnv")
|
||||
or getTarget().hasQualifiedName("_wspawnve")
|
||||
or getTarget().hasQualifiedName("_wspawnvp")
|
||||
or getTarget().hasQualifiedName("_wspawnvpe")
|
||||
or getTarget().hasGlobalName("_execv")
|
||||
or getTarget().hasGlobalName("_execve")
|
||||
or getTarget().hasGlobalName("_execvp")
|
||||
or getTarget().hasGlobalName("_execvpe")
|
||||
or getTarget().hasGlobalName("_spawnv")
|
||||
or getTarget().hasGlobalName("_spawnve")
|
||||
or getTarget().hasGlobalName("_spawnvp")
|
||||
or getTarget().hasGlobalName("_spawnvpe")
|
||||
or getTarget().hasGlobalName("_wexecv")
|
||||
or getTarget().hasGlobalName("_wexecve")
|
||||
or getTarget().hasGlobalName("_wexecvp")
|
||||
or getTarget().hasGlobalName("_wexecvpe")
|
||||
or getTarget().hasGlobalName("_wspawnv")
|
||||
or getTarget().hasGlobalName("_wspawnve")
|
||||
or getTarget().hasGlobalName("_wspawnvp")
|
||||
or getTarget().hasGlobalName("_wspawnvpe")
|
||||
}
|
||||
|
||||
/** The argument with the array of command arguments */
|
||||
@@ -137,8 +137,8 @@ class ArrayExecFunctionCall extends FunctionCall {
|
||||
* all the other ones start with the command. */
|
||||
private int getCommandIdx() {
|
||||
if (
|
||||
getTarget().getQualifiedName().matches("\\_spawn%")
|
||||
or getTarget().getQualifiedName().matches("\\_wspawn%"))
|
||||
getTarget().getName().matches("\\_spawn%")
|
||||
or getTarget().getName().matches("\\_wspawn%"))
|
||||
then result = 1
|
||||
else result = 0
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ private predicate fileStreamChain(ChainedOutputCall out, Expr source, Expr dest)
|
||||
*/
|
||||
private predicate fileWrite(Call write, Expr source, Expr dest) {
|
||||
exists(Function f, int s, int d | f = write.getTarget() and source = write.getArgument(s) and dest = write.getArgument(d) |
|
||||
exists(string name | name = f.getQualifiedName() |
|
||||
exists(string name | f.hasGlobalName(name) |
|
||||
// named functions
|
||||
name = "fwrite" and s = 0 and d = 3 or
|
||||
(
|
||||
@@ -165,14 +165,7 @@ private predicate fileWrite(Call write, Expr source, Expr dest) {
|
||||
name = "putc" or
|
||||
name = "putwc" or
|
||||
name = "putw"
|
||||
) and s = 0 and d = 1 or
|
||||
name.matches("NSFileManager%::-createFileAtPath:contents:attributes:") and s = 1 and d = 0 or
|
||||
(
|
||||
// methods that write into the receiver
|
||||
dest = write.getQualifier() and
|
||||
source = write.getArgument(0) and
|
||||
name.matches("NSFileHandle%::-writeData:")
|
||||
)
|
||||
) and s = 0 and d = 1
|
||||
) or (
|
||||
// fprintf
|
||||
s >= f.(Fprintf).getFormatParameterIndex() and
|
||||
|
||||
@@ -66,8 +66,8 @@ private predicate outputWrite(Expr write, Expr source) {
|
||||
) or (
|
||||
// puts, putchar
|
||||
(
|
||||
f.getQualifiedName() = "puts" or
|
||||
f.getQualifiedName() = "putchar"
|
||||
f.hasGlobalName("puts") or
|
||||
f.hasGlobalName("putchar")
|
||||
) and arg = 0
|
||||
) or exists(Call wrappedCall, Expr wrappedSource |
|
||||
// wrapped output call (recursive case)
|
||||
|
||||
Reference in New Issue
Block a user