Merge pull request #1303 from jbj/hasQualifiedName

C++: Fix `getQualifiedName` performance issues
This commit is contained in:
Robert Marsh
2019-05-15 12:42:57 -07:00
committed by GitHub
50 changed files with 743 additions and 298 deletions

View File

@@ -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

View File

@@ -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
)
}

View File

@@ -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

View File

@@ -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))
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.
}

View File

@@ -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

View File

@@ -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
(

View File

@@ -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")
}
}

View File

@@ -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")
}
}

View File

@@ -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() {

View File

@@ -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"
)
}

View File

@@ -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 |

View File

@@ -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. */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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).
*

View File

@@ -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()
)
}
}

View File

@@ -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() {

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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)
)
)

View File

@@ -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.
*/

View File

@@ -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")
}
/**

View File

@@ -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

View File

@@ -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

View 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()
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -588,7 +588,7 @@ predicate allocateDescriptorCall(FunctionCall fc)
{
exists(string name |
name = "socket" and
fc.getTarget().hasQualifiedName(name))
fc.getTarget().hasGlobalName(name))
}
/**

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)