Skip to content
Merged
2 changes: 2 additions & 0 deletions change-notes/1.21/analysis-cpp.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
| `()`-declared function called with too many arguments (`cpp/futile-params`) | Improved coverage | Query has been generalized to find all cases where the number of arguments exceedes the number of parameters of the function, provided the function is also properly declared/defined elsewhere. |

## Changes to QL libraries
- The predicate `Declaration.hasGlobalName` now only holds for declarations that are not nested in a class. For example, it no longer holds for a member function `MyClass::myFunction` or a constructor `MyClass::MyClass`, whereas previously it would classify those two declarations as global names.
- In class `Declaration`, predicates `getQualifiedName/0` and `hasQualifiedName/1` are no longer recommended for finding functions by name. Instead, use `hasGlobalName/1` and the new `hasQualifiedName/2` and `hasQualifiedName/3` predicates. This improves performance and makes it more reliable to identify names involving templates.
- Additional support for definition by reference has been added to the `semmle.code.cpp.dataflow.TaintTracking` library.
- The taint tracking library now includes taint-specific edges for functions modeled in `semmle.code.cpp.models.interfaces.DataFlow`.
- The taint tracking library adds flow through library functions that are modeled in `semmle.code.cpp.models.interfaces.Taint`. Queries can add subclasses of `TaintFunction` to specify additional flow.
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/Critical/DescriptorNeverClosed.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
}
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/Critical/GlobalUseBeforeInit.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/Critical/InitialisationNotRun.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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)
Expand Down
12 changes: 6 additions & 6 deletions cpp/ql/src/Critical/OverflowCalculated.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/Critical/OverflowDestination.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions cpp/ql/src/Critical/OverflowStatic.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/src/Critical/SizeCheck.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/src/Critical/SizeCheck2.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/Critical/UseAfterFree.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions cpp/ql/src/DefaultOptions.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
}

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
Expand Down
7 changes: 2 additions & 5 deletions cpp/ql/src/Metrics/Files/FNumberOfTests.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 2 additions & 5 deletions cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
(
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}

Expand Down
6 changes: 3 additions & 3 deletions cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}

Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
)
}
Expand Down
6 changes: 3 additions & 3 deletions cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 |
Expand Down
Loading