mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge branch 'codeql-cli-2.18.2' into dbartol/csharp-test-hotfix
This commit is contained in:
@@ -14,7 +14,7 @@ local_path_override(
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.10")
|
||||
bazel_dep(name = "rules_go", version = "0.48.0")
|
||||
bazel_dep(name = "rules_go", version = "0.49.0")
|
||||
bazel_dep(name = "rules_pkg", version = "0.10.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
|
||||
bazel_dep(name = "rules_python", version = "0.32.2")
|
||||
@@ -23,10 +23,10 @@ bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.37.0")
|
||||
bazel_dep(name = "gazelle", version = "0.38.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.15.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.46.0")
|
||||
bazel_dep(name = "rules_rust", version = "0.49.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
|
||||
2296
cpp/downgrades/25e365d1e8147df0f759b604f96eb4bffea48271/old.dbscheme
Normal file
2296
cpp/downgrades/25e365d1e8147df0f759b604f96eb4bffea48271/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
description: Revert support for using-enum declarations.
|
||||
compatibility: partial
|
||||
usings.rel: run usings.qlo
|
||||
using_container.rel: run using_container.qlo
|
||||
@@ -0,0 +1,14 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element parent, int kind
|
||||
where
|
||||
usings(u, _, _, kind) and
|
||||
using_container(parent, u) and
|
||||
kind != 3
|
||||
select parent, u
|
||||
@@ -0,0 +1,17 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element target, Location loc, int kind
|
||||
where
|
||||
usings(u, target, loc, kind) and
|
||||
kind != 3
|
||||
select u, target, loc
|
||||
2310
cpp/downgrades/68930f3b81bbe3fdbb91c850deca1fec8072d62a/old.dbscheme
Normal file
2310
cpp/downgrades/68930f3b81bbe3fdbb91c850deca1fec8072d62a/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: description: Support explicit(bool) specifiers
|
||||
compatibility: full
|
||||
explicit_specifier_exprs.rel: delete
|
||||
2300
cpp/downgrades/9629fc87dab7dbed0771bf5ce22bce4d7f943b52/old.dbscheme
Normal file
2300
cpp/downgrades/9629fc87dab7dbed0771bf5ce22bce4d7f943b52/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support destroying deletes
|
||||
compatibility: full
|
||||
2305
cpp/downgrades/e197626a6ebccd052d5c891975fccf8aebcc9803/old.dbscheme
Normal file
2305
cpp/downgrades/e197626a6ebccd052d5c891975fccf8aebcc9803/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Add relation between deduction guides and class templates
|
||||
compatibility: full
|
||||
deduction_guide_for_class.rel: delete
|
||||
@@ -1,3 +1,18 @@
|
||||
## 1.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
|
||||
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
|
||||
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
|
||||
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
|
||||
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
|
||||
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.
|
||||
|
||||
## 1.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
14
cpp/ql/lib/change-notes/released/1.4.0.md
Normal file
14
cpp/ql/lib/change-notes/released/1.4.0.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## 1.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
|
||||
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
|
||||
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
|
||||
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
|
||||
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
|
||||
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.3.0
|
||||
lastReleaseVersion: 1.4.0
|
||||
|
||||
14
cpp/ql/lib/ext/std.format.model.yml
Normal file
14
cpp/ql/lib/ext/std.format.model.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*1]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*2]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*3]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*4]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*5]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*6]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*7]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*8]", "ReturnValue", "taint", "manual"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 1.3.0
|
||||
version: 1.4.0
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -158,6 +158,26 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
*/
|
||||
predicate isConsteval() { this.hasSpecifier("is_consteval") }
|
||||
|
||||
/**
|
||||
* Holds if this function is declared to be `explicit`.
|
||||
*/
|
||||
predicate isExplicit() { this.hasSpecifier("explicit") }
|
||||
|
||||
/**
|
||||
* Gets the constant expression that determines whether the function is explicit.
|
||||
*
|
||||
* For example, for the following code the result is the expression `sizeof(T) == 1`:
|
||||
* ```
|
||||
* template<typename T> struct C {
|
||||
* explicit(sizeof(T) == 1)
|
||||
* C(const T);
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
Expr getExplicitExpr() {
|
||||
explicit_specifier_exprs(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function is declared with `__attribute__((naked))` or
|
||||
* `__declspec(naked)`.
|
||||
@@ -898,4 +918,11 @@ class UserDefinedLiteral extends Function {
|
||||
*/
|
||||
class DeductionGuide extends Function {
|
||||
DeductionGuide() { functions(underlyingElement(this), _, 8) }
|
||||
|
||||
/**
|
||||
* Gets the class template for which this is a deduction guide.
|
||||
*/
|
||||
TemplateClass getTemplateClass() {
|
||||
deduction_guide_for_class(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
|
||||
* A C++ `using` directive or `using` declaration.
|
||||
*/
|
||||
class UsingEntry extends Locatable, @using {
|
||||
override Location getLocation() { usings(underlyingElement(this), _, result) }
|
||||
override Location getLocation() { usings(underlyingElement(this), _, result, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,15 +166,13 @@ class UsingEntry extends Locatable, @using {
|
||||
* ```
|
||||
*/
|
||||
class UsingDeclarationEntry extends UsingEntry {
|
||||
UsingDeclarationEntry() {
|
||||
not exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
|
||||
}
|
||||
UsingDeclarationEntry() { usings(underlyingElement(this), _, _, 1) }
|
||||
|
||||
/**
|
||||
* Gets the declaration that is referenced by this using declaration. For
|
||||
* example, `std::string` in `using std::string`.
|
||||
*/
|
||||
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) }
|
||||
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
override string toString() { result = "using " + this.getDeclaration().getDescription() }
|
||||
}
|
||||
@@ -186,19 +184,36 @@ class UsingDeclarationEntry extends UsingEntry {
|
||||
* ```
|
||||
*/
|
||||
class UsingDirectiveEntry extends UsingEntry {
|
||||
UsingDirectiveEntry() {
|
||||
exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
|
||||
}
|
||||
UsingDirectiveEntry() { usings(underlyingElement(this), _, _, 2) }
|
||||
|
||||
/**
|
||||
* Gets the namespace that is referenced by this using directive. For
|
||||
* example, `std` in `using namespace std`.
|
||||
*/
|
||||
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) }
|
||||
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `using enum` declaration. For example:
|
||||
* ```
|
||||
* enum class Foo { a, b };
|
||||
* using enum Foo;
|
||||
* ```
|
||||
*/
|
||||
class UsingEnumDeclarationEntry extends UsingEntry {
|
||||
UsingEnumDeclarationEntry() { usings(underlyingElement(this), _, _, 3) }
|
||||
|
||||
/**
|
||||
* Gets the enumeration that is referenced by this using directive. For
|
||||
* example, `Foo` in `using enum Foo`.
|
||||
*/
|
||||
Enum getEnum() { usings(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
override string toString() { result = "using enum " + this.getEnum().getQualifiedName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `g` is an instance of `GlobalNamespace`. This predicate
|
||||
* is used suppress a warning in `GlobalNamespace.getADeclaration()`
|
||||
|
||||
@@ -435,12 +435,17 @@ private predicate elementSpec(
|
||||
}
|
||||
|
||||
/** Gets the fully templated version of `f`. */
|
||||
private Function getFullyTemplatedMemberFunction(Function f) {
|
||||
private Function getFullyTemplatedFunction(Function f) {
|
||||
not f.isFromUninstantiatedTemplate(_) and
|
||||
exists(Class c, Class templateClass, int i |
|
||||
c.isConstructedFrom(templateClass) and
|
||||
f = c.getAMember(i) and
|
||||
result = templateClass.getCanonicalMember(i)
|
||||
(
|
||||
exists(Class c, Class templateClass, int i |
|
||||
c.isConstructedFrom(templateClass) and
|
||||
f = c.getAMember(i) and
|
||||
result = templateClass.getCanonicalMember(i)
|
||||
)
|
||||
or
|
||||
not exists(f.getDeclaringType()) and
|
||||
f.isConstructedFrom(result)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -464,14 +469,14 @@ string getParameterTypeWithoutTemplateArguments(Function f, int n) {
|
||||
*/
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedMemberFunction(f) and
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
remaining = templateFunction.getNumberOfTemplateArguments() and
|
||||
result = getParameterTypeWithoutTemplateArguments(templateFunction, n)
|
||||
)
|
||||
or
|
||||
exists(string mid, TemplateParameter tp, Function templateFunction |
|
||||
mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and
|
||||
templateFunction = getFullyTemplatedMemberFunction(f) and
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
tp = templateFunction.getTemplateArgument(remaining) and
|
||||
result = mid.replaceAll(tp.getName(), "func:" + remaining.toString())
|
||||
)
|
||||
@@ -482,12 +487,18 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain
|
||||
* with `class:N` (where `N` is the index of the template).
|
||||
*/
|
||||
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
|
||||
// If there is a declaring type then we start by expanding the function templates
|
||||
exists(Class template |
|
||||
f.getDeclaringType().isConstructedFrom(template) and
|
||||
remaining = template.getNumberOfTemplateArguments() and
|
||||
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
|
||||
)
|
||||
or
|
||||
// If there is no declaring type we're done after expanding the function templates
|
||||
not exists(f.getDeclaringType()) and
|
||||
remaining = 0 and
|
||||
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
|
||||
or
|
||||
exists(string mid, TemplateParameter tp, Class template |
|
||||
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
|
||||
f.getDeclaringType().isConstructedFrom(template) and
|
||||
@@ -570,38 +581,6 @@ private string getSignatureWithoutFunctionTemplateNames(
|
||||
)
|
||||
}
|
||||
|
||||
private string paramsStringPart(Function c, int i) {
|
||||
not c.isFromUninstantiatedTemplate(_) and
|
||||
(
|
||||
i = -1 and result = "(" and exists(c)
|
||||
or
|
||||
exists(int n, string p | getParameterTypeName(c, n) = p |
|
||||
i = 2 * n and result = p
|
||||
or
|
||||
i = 2 * n - 1 and result = "," and n != 0
|
||||
)
|
||||
or
|
||||
i = 2 * c.getNumberOfParameters() and result = ")"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
|
||||
*
|
||||
* Returns the empty string if the callable has no parameters.
|
||||
* Parameter types are represented by their type erasure.
|
||||
*/
|
||||
cached
|
||||
private string paramsString(Function c) {
|
||||
result = concat(int i | | paramsStringPart(c, i) order by i)
|
||||
}
|
||||
|
||||
bindingset[func]
|
||||
private predicate matchesSignature(Function func, string signature) {
|
||||
signature = "" or
|
||||
paramsString(func) = signature
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `elementSpec(_, type, _, name, signature, _)` holds and
|
||||
* - `typeArgs` represents the named template parameters supplied to `type`, and
|
||||
@@ -750,17 +729,17 @@ private predicate elementSpecWithArguments0(
|
||||
|
||||
/**
|
||||
* Holds if `elementSpec(namespace, type, subtypes, name, signature, _)` and
|
||||
* `method`'s signature matches `signature`.
|
||||
* `func`'s signature matches `signature`.
|
||||
*
|
||||
* `signature` may contain template parameter names that are bound by `type` and `name`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate elementSpecMatchesSignature(
|
||||
Function method, string namespace, string type, boolean subtypes, string name, string signature
|
||||
Function func, string namespace, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
elementSpec(namespace, pragma[only_bind_into](type), subtypes, pragma[only_bind_into](name),
|
||||
pragma[only_bind_into](signature), _) and
|
||||
signatureMatches(method, signature, type, name, 0)
|
||||
signatureMatches(func, signature, type, name, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -776,13 +755,22 @@ private predicate hasClassAndName(Class classWithMethod, Function method, string
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[name]
|
||||
pragma[inline_late]
|
||||
private predicate funcHasQualifiedName(Function func, string namespace, string name) {
|
||||
exists(string nameWithoutArgs |
|
||||
parseAngles(name, nameWithoutArgs, _, "") and
|
||||
func.hasQualifiedName(namespace, nameWithoutArgs)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `namedClass` is in namespace `namespace` and has
|
||||
* name `type` (excluding any template parameters).
|
||||
*/
|
||||
bindingset[type, namespace]
|
||||
pragma[inline_late]
|
||||
private predicate hasQualifiedName(Class namedClass, string namespace, string type) {
|
||||
private predicate classHasQualifiedName(Class namedClass, string namespace, string type) {
|
||||
exists(string typeWithoutArgs |
|
||||
parseAngles(type, typeWithoutArgs, _, "") and
|
||||
namedClass.hasQualifiedName(namespace, typeWithoutArgs)
|
||||
@@ -804,15 +792,16 @@ private Element interpretElement0(
|
||||
string namespace, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
(
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
// Non-member functions
|
||||
exists(Function func |
|
||||
func.hasQualifiedName(namespace, name) and
|
||||
type = "" and
|
||||
matchesSignature(func, signature) and
|
||||
subtypes = false and
|
||||
not exists(func.getDeclaringType()) and
|
||||
result = func
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
subtypes = false and
|
||||
type = "" and
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
or
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
funcHasQualifiedName(result, namespace, name)
|
||||
)
|
||||
or
|
||||
// Member functions
|
||||
@@ -825,7 +814,7 @@ private Element interpretElement0(
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
hasClassAndName(classWithMethod, result, name)
|
||||
) and
|
||||
hasQualifiedName(namedClass, namespace, type) and
|
||||
classHasQualifiedName(namedClass, namespace, type) and
|
||||
(
|
||||
// member declared in the named type or a subtype of it
|
||||
subtypes = true and
|
||||
|
||||
@@ -215,19 +215,16 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
predicate localMustFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Type getNodeType(Node n) {
|
||||
DataFlowType getNodeType(Node n) {
|
||||
exists(n) and
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(Type t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
predicate compatibleTypes(Type t1, Type t2) {
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
@@ -243,7 +240,11 @@ class DataFlowCallable extends Function { }
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
final private class TypeFinal = Type;
|
||||
|
||||
class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends Expr instanceof Call {
|
||||
|
||||
@@ -307,6 +307,10 @@ class Expr extends StmtParent, @expr {
|
||||
)
|
||||
or
|
||||
exists(Decltype d | d.getExpr() = this.getParentWithConversions*())
|
||||
or
|
||||
exists(ConstexprIfStmt constIf |
|
||||
constIf.getControllingExpr() = this.getParentWithConversions*()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,6 +859,16 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the deallocation function is a destroying delete.
|
||||
*/
|
||||
predicate isDestroyingDeleteDeallocation() {
|
||||
exists(int form |
|
||||
expr_deallocator(underlyingElement(this), _, form) and
|
||||
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type that is being allocated.
|
||||
*
|
||||
@@ -1025,6 +1039,16 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the deallocation function is a destroying delete.
|
||||
*/
|
||||
predicate isDestroyingDeleteDeallocation() {
|
||||
exists(int form |
|
||||
expr_deallocator(underlyingElement(this), _, form) and
|
||||
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object or array being deleted.
|
||||
*/
|
||||
|
||||
@@ -994,9 +994,6 @@ DataFlowType getNodeType(Node n) {
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(DataFlowType t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
@@ -1097,7 +1094,11 @@ class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
final private class TypeFinal = Type;
|
||||
|
||||
class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
|
||||
@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
not instr.isResultModeled()
|
||||
}
|
||||
|
||||
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
|
||||
private predicate consumedAsAddressOperand(Operand operand) {
|
||||
operand instanceof AddressOperand
|
||||
or
|
||||
exists(Operand address |
|
||||
consumedAsAddressOperand(address) and
|
||||
operandIsPropagated(operand, _, address.getDef())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` may originate from a base instruction of an allocation,
|
||||
* and that operand may transitively flow to an `AddressOperand`.
|
||||
*/
|
||||
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
|
||||
consumedAsAddressOperand(operand) and
|
||||
(
|
||||
not exists(Configuration::getOldAllocation(allocation)) and
|
||||
operand.getDef() = allocation.getABaseInstruction()
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromAllocationBase(address, allocation)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate propagatedFromNonAllocationBase(Operand operand) {
|
||||
exists(Instruction def |
|
||||
def = operand.getDef() and
|
||||
not operandIsPropagated(_, _, def) and
|
||||
not def = any(Configuration::Allocation allocation).getABaseInstruction()
|
||||
)
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we cannot see all producers of an operand for which allocation also flows into.
|
||||
*/
|
||||
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
|
||||
exists(AddressOperand address |
|
||||
propagatedFromAllocationBase(address, allocation) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
|
||||
* either because the allocation's address is taken within the function and escapes, or because the
|
||||
@@ -346,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
allocation.alwaysEscapes()
|
||||
or
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
or
|
||||
operandConsumesEscaped(allocation)
|
||||
)
|
||||
or
|
||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -146,3 +146,8 @@ class DynamicAllocation extends Allocation, TDynamicAllocation {
|
||||
}
|
||||
|
||||
predicate phaseNeedsSoundEscapeAnalysis() { none() }
|
||||
|
||||
UnaliasedSsa::Allocation getOldAllocation(VariableAllocation allocation) {
|
||||
UnaliasedSsa::canReuseSsaForVariable(allocation.getIRVariable()) and
|
||||
result = allocation.getIRVariable()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConst
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import AliasConfiguration
|
||||
import AliasConfiguration
|
||||
private import codeql.util.Boolean
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
@@ -227,13 +227,15 @@ private newtype TMemoryLocation =
|
||||
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
|
||||
|
||||
/**
|
||||
* Represents the memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* one of the following:
|
||||
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
||||
* unknown.
|
||||
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
|
||||
*
|
||||
* Some of these memory locations will be filtered out for performance reasons before being passed to SSA construction.
|
||||
*/
|
||||
abstract class MemoryLocation extends TMemoryLocation {
|
||||
abstract private class MemoryLocation0 extends TMemoryLocation {
|
||||
final string toString() {
|
||||
if this.isMayAccess()
|
||||
then result = "?" + this.toStringInternal()
|
||||
@@ -294,9 +296,9 @@ abstract class MemoryLocation extends TMemoryLocation {
|
||||
* represented by a `MemoryLocation` that totally overlaps all other
|
||||
* `MemoryLocations` in the set.
|
||||
*/
|
||||
abstract class VirtualVariable extends MemoryLocation { }
|
||||
abstract class VirtualVariable extends MemoryLocation0 { }
|
||||
|
||||
abstract class AllocationMemoryLocation extends MemoryLocation {
|
||||
abstract class AllocationMemoryLocation extends MemoryLocation0 {
|
||||
Allocation var;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -424,7 +426,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
|
||||
* `{a, b}` into a memory location that represents _all_ of the allocations
|
||||
* in the set.
|
||||
*/
|
||||
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation {
|
||||
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation0 {
|
||||
VariableGroup vg;
|
||||
boolean isMayAccess;
|
||||
boolean isAll;
|
||||
@@ -528,7 +530,7 @@ class GroupedVirtualVariable extends GroupedMemoryLocation, VirtualVariable {
|
||||
/**
|
||||
* An access to memory that is not known to be confined to a specific `IRVariable`.
|
||||
*/
|
||||
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
|
||||
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -555,7 +557,7 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
|
||||
* An access to memory that is not known to be confined to a specific `IRVariable`, but is known to
|
||||
* not access memory on the current function's stack frame.
|
||||
*/
|
||||
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
||||
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -589,7 +591,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
||||
/**
|
||||
* An access to all aliased memory.
|
||||
*/
|
||||
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
|
||||
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -620,7 +622,7 @@ class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
|
||||
/**
|
||||
* Gets the overlap relationship between the definition location `def` and the use location `use`.
|
||||
*/
|
||||
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
Overlap getOverlap(MemoryLocation0 def, MemoryLocation0 use) {
|
||||
exists(Overlap overlap |
|
||||
// Compute the overlap based only on the extent.
|
||||
overlap = getExtentOverlap(def, use) and
|
||||
@@ -648,7 +650,7 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
* based only on the set of memory locations accessed. Handling of "may" accesses and read-only
|
||||
* locations occurs in `getOverlap()`.
|
||||
*/
|
||||
private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
|
||||
// The def and the use must have the same virtual variable, or no overlap is possible.
|
||||
(
|
||||
// AllAliasedMemory must totally overlap any location within the same virtual variable.
|
||||
@@ -861,6 +863,40 @@ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMem
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/** Gets the number of overlapping uses of `def`. */
|
||||
private int numberOfOverlappingUses(MemoryLocation0 def) {
|
||||
result = strictcount(MemoryLocation0 use | exists(getOverlap(def, use)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is a busy definition. That is, it has a large number of
|
||||
* overlapping uses.
|
||||
*/
|
||||
private predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
|
||||
|
||||
/** Holds if `use` is a use that overlaps with a busy definition. */
|
||||
private predicate useOverlapWithBusyDef(MemoryLocation0 use) {
|
||||
exists(MemoryLocation0 def |
|
||||
exists(getOverlap(def, use)) and
|
||||
isBusyDef(def)
|
||||
)
|
||||
}
|
||||
|
||||
final private class FinalMemoryLocation = MemoryLocation0;
|
||||
|
||||
/**
|
||||
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* one of the following:
|
||||
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
||||
* unknown.
|
||||
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
|
||||
*
|
||||
* Compared to `MemoryLocation0`, this class does not contain memory locations that represent uses of busy definitions.
|
||||
*/
|
||||
class MemoryLocation extends FinalMemoryLocation {
|
||||
MemoryLocation() { not useOverlapWithBusyDef(this) }
|
||||
}
|
||||
|
||||
MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
not canReuseSsaForOldResult(instr) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
@@ -905,9 +941,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
)
|
||||
}
|
||||
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
private MemoryLocation0 getOperandMemoryLocation0(MemoryOperand operand, boolean isMayAccess) {
|
||||
not canReuseSsaForOldResult(operand.getAnyDef()) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
exists(MemoryAccessKind kind |
|
||||
kind = operand.getMemoryAccess() and
|
||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
(
|
||||
@@ -948,6 +984,19 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
)
|
||||
}
|
||||
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
exists(MemoryLocation0 use0, boolean isMayAccess |
|
||||
use0 = getOperandMemoryLocation0(operand, isMayAccess)
|
||||
|
|
||||
result = use0
|
||||
or
|
||||
// If `use0` overlaps with a busy definition we turn it into a use
|
||||
// of `UnknownMemoryLocation`.
|
||||
not use0 instanceof MemoryLocation and
|
||||
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||
int getStartBitOffset(VariableMemoryLocation location) {
|
||||
result = location.getStartBitOffset() and Ints::hasValue(result)
|
||||
|
||||
@@ -933,11 +933,15 @@ module DefUse {
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getNonChiOffset(int index, OldBlock block) {
|
||||
exists(IRFunction func | func = block.getEnclosingIRFunction() |
|
||||
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
|
||||
func = block.getEnclosingIRFunction() and
|
||||
i = block.getInstruction(index) and
|
||||
entryBlock = func.getEntryBlock()
|
||||
|
|
||||
if
|
||||
getNewBlock(block) = func.getEntryBlock() and
|
||||
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
|
||||
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
|
||||
block = entryBlock and
|
||||
not i instanceof InitializeNonLocalInstruction and
|
||||
not i instanceof AliasedDefinitionInstruction
|
||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||
else result = 2 * index
|
||||
)
|
||||
|
||||
@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
not instr.isResultModeled()
|
||||
}
|
||||
|
||||
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
|
||||
private predicate consumedAsAddressOperand(Operand operand) {
|
||||
operand instanceof AddressOperand
|
||||
or
|
||||
exists(Operand address |
|
||||
consumedAsAddressOperand(address) and
|
||||
operandIsPropagated(operand, _, address.getDef())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` may originate from a base instruction of an allocation,
|
||||
* and that operand may transitively flow to an `AddressOperand`.
|
||||
*/
|
||||
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
|
||||
consumedAsAddressOperand(operand) and
|
||||
(
|
||||
not exists(Configuration::getOldAllocation(allocation)) and
|
||||
operand.getDef() = allocation.getABaseInstruction()
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromAllocationBase(address, allocation)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate propagatedFromNonAllocationBase(Operand operand) {
|
||||
exists(Instruction def |
|
||||
def = operand.getDef() and
|
||||
not operandIsPropagated(_, _, def) and
|
||||
not def = any(Configuration::Allocation allocation).getABaseInstruction()
|
||||
)
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we cannot see all producers of an operand for which allocation also flows into.
|
||||
*/
|
||||
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
|
||||
exists(AddressOperand address |
|
||||
propagatedFromAllocationBase(address, allocation) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
|
||||
* either because the allocation's address is taken within the function and escapes, or because the
|
||||
@@ -346,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
allocation.alwaysEscapes()
|
||||
or
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
or
|
||||
operandConsumesEscaped(allocation)
|
||||
)
|
||||
or
|
||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
private import AliasConfigurationImports
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A memory allocation that can be tracked by the SimpleSSA alias analysis.
|
||||
@@ -16,3 +17,5 @@ class Allocation extends IRAutomaticVariable {
|
||||
}
|
||||
|
||||
predicate phaseNeedsSoundEscapeAnalysis() { any() }
|
||||
|
||||
Unit getOldAllocation(Allocation allocation) { any() }
|
||||
|
||||
@@ -933,11 +933,15 @@ module DefUse {
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getNonChiOffset(int index, OldBlock block) {
|
||||
exists(IRFunction func | func = block.getEnclosingIRFunction() |
|
||||
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
|
||||
func = block.getEnclosingIRFunction() and
|
||||
i = block.getInstruction(index) and
|
||||
entryBlock = func.getEntryBlock()
|
||||
|
|
||||
if
|
||||
getNewBlock(block) = func.getEntryBlock() and
|
||||
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
|
||||
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
|
||||
block = entryBlock and
|
||||
not i instanceof InitializeNonLocalInstruction and
|
||||
not i instanceof AliasedDefinitionInstruction
|
||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||
else result = 2 * index
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import AliasAnalysis
|
||||
private import SimpleSSAImports
|
||||
import SimpleSSAPublicImports
|
||||
private import AliasConfiguration
|
||||
import AliasConfiguration
|
||||
private import codeql.util.Unit
|
||||
|
||||
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
|
||||
|
||||
@@ -27,6 +27,11 @@ private import implementations.StdPair
|
||||
private import implementations.StdMap
|
||||
private import implementations.StdSet
|
||||
private import implementations.StdString
|
||||
private import implementations.StdFunction
|
||||
private import implementations.StdException
|
||||
private import implementations.StdAllocator
|
||||
private import implementations.StdAlgorithm
|
||||
private import implementations.StdMath
|
||||
private import implementations.Swap
|
||||
private import implementations.GetDelim
|
||||
private import implementations.SmartPointer
|
||||
|
||||
@@ -86,6 +86,41 @@ private class StdIterator extends Iterator, Class {
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdReverseIterator extends Iterator, Class {
|
||||
StdReverseIterator() { this.hasQualifiedName(["std", "bsl"], "reverse_iterator") }
|
||||
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdIstreamBufIterator extends Iterator, Class {
|
||||
StdIstreamBufIterator() { this.hasQualifiedName(["std", "bsl"], "istreambuf_iterator") }
|
||||
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdIstreambufIteratorConstructor extends Constructor, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdIstreambufIteratorConstructor() { this.getDeclaringType() instanceof StdIstreamBufIterator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `FunctionInput` corresponding to an iterator parameter to
|
||||
* user-defined operator `op`, at `index`.
|
||||
@@ -579,23 +614,43 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
|
||||
}
|
||||
|
||||
private string beginName() {
|
||||
result = ["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]
|
||||
}
|
||||
|
||||
/**
|
||||
* A `begin` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class BeginFunction extends MemberFunction {
|
||||
class BeginFunction extends Function {
|
||||
BeginFunction() {
|
||||
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this.getUnspecifiedType() instanceof Iterator and
|
||||
(
|
||||
this.hasName(beginName()) and
|
||||
this instanceof MemberFunction
|
||||
or
|
||||
this.hasGlobalOrStdOrBslName(beginName()) and
|
||||
not this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private string endName() { result = ["end", "cend", "rend", "crend"] }
|
||||
|
||||
/**
|
||||
* An `end` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class EndFunction extends MemberFunction {
|
||||
class EndFunction extends Function {
|
||||
EndFunction() {
|
||||
this.hasName(["end", "cend", "rend", "crend"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this.getUnspecifiedType() instanceof Iterator and
|
||||
(
|
||||
this.hasName(endName()) and
|
||||
this instanceof MemberFunction
|
||||
or
|
||||
this.hasGlobalOrStdOrBslName(endName()) and
|
||||
this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,7 +658,7 @@ class EndFunction extends MemberFunction {
|
||||
* A `begin` or `end` member function, or a related member function, that
|
||||
* returns an iterator.
|
||||
*/
|
||||
class BeginOrEndFunction extends MemberFunction {
|
||||
class BeginOrEndFunction extends Function {
|
||||
BeginOrEndFunction() {
|
||||
this instanceof BeginFunction or
|
||||
this instanceof EndFunction
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||
@@ -96,7 +97,7 @@ private class Sprintf extends FormattingFunction {
|
||||
/**
|
||||
* Implements `Snprintf`.
|
||||
*/
|
||||
private class SnprintfImpl extends Snprintf {
|
||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
|
||||
SnprintfImpl() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -143,6 +144,26 @@ private class SnprintfImpl extends Snprintf {
|
||||
}
|
||||
|
||||
override int getSizeParameterIndex() { result = 1 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
// We don't know how many parameters are passed to the function since it's varargs, but they also don't escape.
|
||||
index = this.getFormatParameterIndex()
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getOutputParameterIndex(false) and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// We don't know how many parameters are passed to the function since it's varargs, but they also have read side effects.
|
||||
i = this.getFormatParameterIndex() and buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Provides models for C++ functions from the `algorithms` header.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class StdPartialSort extends Function, SideEffectFunction, AliasFunction {
|
||||
StdPartialSort() { this.hasGlobalOrStdName("partial_sort") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and
|
||||
buffer = true and
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
index = this.getAnIteratorParameterIndex()
|
||||
or
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdSortHeap extends Function, SideEffectFunction, AliasFunction {
|
||||
StdSortHeap() { this.hasGlobalOrStdName("sort_heap") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdGenerateN extends Function, SideEffectFunction, AliasFunction {
|
||||
StdGenerateN() { this.hasGlobalOrStdName("generate_n") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdFindIfOrIfNot extends Function, SideEffectFunction, AliasFunction {
|
||||
StdFindIfOrIfNot() { this.hasGlobalOrStdName(["find_if", "find_if_not"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true
|
||||
or
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) {
|
||||
index = this.getAnIteratorParameterIndex()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/**
|
||||
* Provides models for C++ `allocator` and `allocator_traits` classes.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/** The `std::allocator` class. */
|
||||
class StdAllocator extends Class {
|
||||
StdAllocator() { this.hasGlobalOrStdOrBslName("allocator") }
|
||||
}
|
||||
|
||||
/** The `std::allocator_traits` class. */
|
||||
class StdAllocatorTraits extends Class {
|
||||
StdAllocatorTraits() { this.hasGlobalOrStdOrBslName("allocator_traits") }
|
||||
}
|
||||
|
||||
private class StdAllocatorConstructor extends Constructor, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorConstructor() { this.getDeclaringType() instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorDestructor extends Destructor, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDestructor() { this.getDeclaringType() instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorAddress extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorAddress() { this.getClassAndName("address") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorAllocate() { this.getClassAndName("allocate") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorTraitsAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsAllocate() {
|
||||
this.getClassAndName(["allocate", "allocate_at_least"]) instanceof StdAllocatorTraits
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorDeallocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDeallocate() { this.getClassAndName("deallocate") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and
|
||||
buffer = false and
|
||||
mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorTraitsDeallocate extends MemberFunction, AliasFunction, SideEffectFunction
|
||||
{
|
||||
StdAllocatorTraitsDeallocate() {
|
||||
this.getClassAndName("deallocate") instanceof StdAllocatorTraits
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and
|
||||
buffer = false and
|
||||
mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorMaxSize() { this.getClassAndName("max_size") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatTraitsMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatTraitsMaxSize() { this.getClassAndName("max_size") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorConstruct() { this.getClassAndName("construct") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorTraitsConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsConstruct() { this.getClassAndName("construct") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
index = 1 or this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDestroy() { this.getClassAndName("destroy") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorTraitsDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsDestroy() { this.getClassAndName("destroy") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* A sequence container template class (for example, `std::vector`) from the
|
||||
@@ -58,7 +60,7 @@ private class Vector extends StdSequenceContainer {
|
||||
/**
|
||||
* The standard container functions `push_back` and `push_front`.
|
||||
*/
|
||||
class StdSequenceContainerPush extends MemberFunction {
|
||||
class StdSequenceContainerPush extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerPush() {
|
||||
this.getClassAndName("push_back") instanceof Vector or
|
||||
this.getClassAndName(["push_back", "push_front"]) instanceof Deque or
|
||||
@@ -74,12 +76,115 @@ class StdSequenceContainerPush extends MemberFunction {
|
||||
this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// the `std::vector<bool>` specialization doesn't take a reference as a
|
||||
// parameter. So we need to check that the parameter is actually a
|
||||
// reference.
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerPopFrontOrBack extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerPopFrontOrBack() {
|
||||
this.getClassAndName("pop_back") instanceof Vector or
|
||||
this.getClassAndName("pop_front") instanceof ForwardList or
|
||||
this.getClassAndName(["pop_front", "pop_back"]) instanceof Deque or
|
||||
this.getClassAndName(["pop_front", "pop_back"]) instanceof List
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerClear extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerClear() {
|
||||
this.getClassAndName("clear") instanceof Vector or
|
||||
this.getClassAndName("clear") instanceof Deque or
|
||||
this.getClassAndName("clear") instanceof ForwardList or
|
||||
this.getClassAndName("clear") instanceof List
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdVectorReserve extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdVectorReserve() { this.getClassAndName("reserve") instanceof Vector }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `insert` and `insert_after`.
|
||||
*/
|
||||
class StdSequenceContainerInsert extends MemberFunction {
|
||||
class StdSequenceContainerInsert extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerInsert() {
|
||||
this.getClassAndName("insert") instanceof Deque or
|
||||
this.getClassAndName("insert") instanceof List or
|
||||
@@ -100,17 +205,138 @@ class StdSequenceContainerInsert extends MemberFunction {
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerFrontBack extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerFrontBack() {
|
||||
this.getClassAndName(["front", "back"]) instanceof Deque or
|
||||
this.getClassAndName(["front", "back"]) instanceof List or
|
||||
this.getClassAndName(["front", "back"]) instanceof Vector or
|
||||
// forward_list does not have a 'back' member function
|
||||
this.getClassAndName("front") instanceof ForwardList
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdSequenceContainerAt extends MemberFunction {
|
||||
class StdSequenceContainerAt extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerAt() {
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Array or
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Deque or
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Vector
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerMemberEquals extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerMemberEquals() {
|
||||
this.getClassAndName("operator==") instanceof Array or
|
||||
this.getClassAndName("operator==") instanceof Deque or
|
||||
this.getClassAndName("operator==") instanceof Vector
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 or index = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
or
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerEquals extends Function, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerEquals() {
|
||||
this.hasGlobalOrStdOrBslName("operator==") and
|
||||
not this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 2 and
|
||||
(
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector
|
||||
or
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List
|
||||
or
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,6 +368,115 @@ class StdVectorEmplace extends StdSequenceEmplace {
|
||||
StdVectorEmplace() { this.getDeclaringType() instanceof Vector }
|
||||
}
|
||||
|
||||
private class StdSequenceSize extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceSize() {
|
||||
this.getClassAndName("size") instanceof Vector
|
||||
or
|
||||
this.getClassAndName("size") instanceof List
|
||||
or
|
||||
this.getClassAndName("size") instanceof Deque
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdSequenceDestructor() {
|
||||
this.getDeclaringType() instanceof Vector
|
||||
or
|
||||
this.getDeclaringType() instanceof List
|
||||
or
|
||||
this.getDeclaringType() instanceof Deque
|
||||
}
|
||||
|
||||
private Destructor getElementDestructor() {
|
||||
result.getDeclaringType() = this.getTemplateArgument(0)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() {
|
||||
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
|
||||
or
|
||||
not exists(this.getElementDestructor())
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
|
||||
or
|
||||
not exists(this.getElementDestructor())
|
||||
}
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdSequenceConstructor() {
|
||||
this.getDeclaringType() instanceof Vector
|
||||
or
|
||||
this.getDeclaringType() instanceof List
|
||||
or
|
||||
this.getDeclaringType() instanceof Deque
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class InitializerList extends Class {
|
||||
InitializerList() { this.hasQualifiedName(["std", "bsl"], "initializer_list") }
|
||||
|
||||
Type getElementType() { result = this.getTemplateArgument(0) }
|
||||
}
|
||||
|
||||
private class InitializerListConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
InitializerListConstructor() { this.getDeclaringType() instanceof InitializerList }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard vector `emplace_back` function.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Provides models for the C++ `std::exception` class and subclasses.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/** The `std::exception` class. */
|
||||
class StdException extends Class {
|
||||
StdException() { this.hasGlobalOrStdOrBslName("exception") }
|
||||
}
|
||||
|
||||
/** The `std::bad_alloc` class. */
|
||||
class StdBadAllocException extends Class {
|
||||
StdBadAllocException() { this.hasGlobalOrStdOrBslName("bad_alloc") }
|
||||
}
|
||||
|
||||
private class StdBadAllocExceptionConstructor extends Constructor, SideEffectFunction, AliasFunction
|
||||
{
|
||||
StdBadAllocExceptionConstructor() { this.getDeclaringType() instanceof StdBadAllocException }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Provides models for C++ `std::function` class.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* An instantiation of the `std::function` class template.
|
||||
*/
|
||||
class StdFunction extends ClassTemplateInstantiation {
|
||||
StdFunction() { this.hasGlobalOrStdOrBslName("function") }
|
||||
}
|
||||
|
||||
private class StdFunctionConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdFunctionConstructor() { this.getDeclaringType() instanceof StdFunction }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdFunctionDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdFunctionDestructor() { this.getDeclaringType() instanceof StdFunction }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* The `std::map` and `std::unordered_map` template classes.
|
||||
@@ -16,7 +18,9 @@ private class MapOrUnorderedMap extends Class {
|
||||
/**
|
||||
* Additional model for map constructors using iterator inputs.
|
||||
*/
|
||||
private class StdMapConstructor extends Constructor, TaintFunction {
|
||||
private class StdMapConstructor extends Constructor, TaintFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
{
|
||||
StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
|
||||
|
||||
/**
|
||||
@@ -35,6 +39,23 @@ private class StdMapConstructor extends Constructor, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +154,7 @@ class StdMapAt extends MemberFunction {
|
||||
StdMapAt() { this.getClassAndName(["at", "operator[]"]) instanceof MapOrUnorderedMap }
|
||||
}
|
||||
|
||||
private class StdMapAtModels extends StdMapAt, TaintFunction {
|
||||
private class StdMapAtModels extends StdMapAt, TaintFunction, AliasFunction, SideEffectFunction {
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
@@ -144,6 +165,18 @@ private class StdMapAtModels extends StdMapAt, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
}
|
||||
|
||||
@@ -187,3 +220,63 @@ private class StdMapEqualRange extends TaintFunction {
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
class StdMapDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdMapDestructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdMapClear extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdMapClear() { this.getClassAndName("clear") instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdMapSize extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdMapSize() { this.getClassAndName("size") instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
108
cpp/ql/lib/semmle/code/cpp/models/implementations/StdMath.qll
Normal file
108
cpp/ql/lib/semmle/code/cpp/models/implementations/StdMath.qll
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Provides models for C++ functions from the `cmath` header.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class LdExp extends Function, SideEffectFunction {
|
||||
LdExp() { this.hasGlobalOrStdOrBslName(["ldexp", "ldexpf", "ldexpl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Abs extends Function, SideEffectFunction {
|
||||
Abs() { this.hasGlobalOrStdOrBslName(["abs", "fabs", "fabsf", "fabsl", "llabs", "imaxabs"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Div extends Function, SideEffectFunction {
|
||||
Div() { this.hasGlobalOrStdOrBslName(["div", "ldiv", "lldiv", "imaxdiv"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class FMod extends Function, SideEffectFunction {
|
||||
FMod() { this.hasGlobalOrStdOrBslName(["fmod", "fmodf", "fmodl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Remainder extends Function, SideEffectFunction {
|
||||
Remainder() { this.hasGlobalOrStdOrBslName(["remainder", "remainderf", "remainderl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Remquo extends Function, SideEffectFunction {
|
||||
Remquo() { this.hasGlobalOrStdOrBslName(["remquo", "remquof", "remquol"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
private class Fma extends Function, SideEffectFunction {
|
||||
Fma() { this.hasGlobalOrStdOrBslName(["fma", "fmaf", "fmal"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fmax extends Function, SideEffectFunction {
|
||||
Fmax() { this.hasGlobalOrStdOrBslName(["fmax", "fmaxf", "fmaxl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fmin extends Function, SideEffectFunction {
|
||||
Fmin() { this.hasGlobalOrStdOrBslName(["fmin", "fminf", "fminl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fdim extends Function, SideEffectFunction {
|
||||
Fdim() { this.hasGlobalOrStdOrBslName(["fdim", "fdimf", "fdiml"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Nan extends Function, SideEffectFunction, AliasFunction {
|
||||
Nan() { this.hasGlobalOrStdOrBslName(["nan", "nanf", "nanl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = true
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* An instantiation of `std::pair<T1, T2>`.
|
||||
@@ -37,7 +39,9 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction {
|
||||
/**
|
||||
* Additional model for `std::pair` constructors.
|
||||
*/
|
||||
private class StdPairConstructor extends Constructor, TaintFunction {
|
||||
private class StdPairConstructor extends Constructor, TaintFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
{
|
||||
StdPairConstructor() { this.getDeclaringType() instanceof StdPair }
|
||||
|
||||
/**
|
||||
@@ -59,4 +63,77 @@ private class StdPairConstructor extends Constructor, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// All the constructor parameters are references with the exception of this one:
|
||||
// ```
|
||||
// template<class... Args1, class... Args2>
|
||||
// pair(std::piecewise_construct_t, std::tuple<Args1...> first_args, std::tuple<Args2...> second_args);
|
||||
// ```
|
||||
// So we need to check that the parameters are actually references
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdPairDestructor extends Destructor, AliasFunction, SideEffectFunction {
|
||||
StdPairDestructor() { this.getDeclaringType() instanceof StdPair }
|
||||
|
||||
private Type getFirstType() { result = this.getDeclaringType().getTemplateArgument(0) }
|
||||
|
||||
private Type getSecondType() { result = this.getDeclaringType().getTemplateArgument(0) }
|
||||
|
||||
private Type getAType() { result = [this.getFirstType(), this.getSecondType()] }
|
||||
|
||||
/**
|
||||
* Gets the destructor associated with the base type of this pair
|
||||
*/
|
||||
private Destructor getADestructor() { result.getDeclaringType() = this.getAType() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() {
|
||||
this.getADestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't have
|
||||
// any strange read side effects.
|
||||
not exists(this.getADestructor())
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
this.getADestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't have
|
||||
// any strange write side effects.
|
||||
not exists(this.getADestructor())
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getADestructor().(AliasFunction).parameterNeverEscapes(index)
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't cause
|
||||
// anything to escape.
|
||||
not exists(this.getADestructor()) and
|
||||
index = -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* The `std::basic_string` template class instantiations.
|
||||
@@ -78,7 +80,9 @@ abstract private class StdStringTaintFunction extends TaintFunction {
|
||||
* std::string b(a.begin(), a.end());
|
||||
* ```
|
||||
*/
|
||||
private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
||||
private class StdStringConstructor extends Constructor, StdStringTaintFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -94,6 +98,42 @@ private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdStringDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdStringDestructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +204,7 @@ private class StdStringFrontBack extends StdStringTaintFunction {
|
||||
/**
|
||||
* The (non-member) `std::string` function `operator+`.
|
||||
*/
|
||||
private class StdStringPlus extends StdStringTaintFunction {
|
||||
private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringPlus() {
|
||||
this.hasQualifiedName(["std", "bsl"], "operator+") and
|
||||
this.getUnspecifiedType() instanceof StdBasicString
|
||||
@@ -178,6 +218,22 @@ private class StdStringPlus extends StdStringTaintFunction {
|
||||
) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
or
|
||||
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +241,7 @@ private class StdStringPlus extends StdStringTaintFunction {
|
||||
* All of these functions combine the existing string with a new
|
||||
* string (or character) from one of the arguments.
|
||||
*/
|
||||
private class StdStringAppend extends StdStringTaintFunction {
|
||||
private class StdStringAppend extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringAppend() {
|
||||
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
|
||||
}
|
||||
@@ -210,6 +266,22 @@ private class StdStringAppend extends StdStringTaintFunction {
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and mustWrite = false and buffer = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [-1, 0] and buffer = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +373,7 @@ private class StdStringSubstr extends StdStringTaintFunction {
|
||||
/**
|
||||
* The `std::string` functions `at` and `operator[]`.
|
||||
*/
|
||||
private class StdStringAt extends StdStringTaintFunction {
|
||||
private class StdStringAt extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -315,6 +387,22 @@ private class StdStringAt extends StdStringTaintFunction {
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,6 +412,54 @@ private class StdBasicIStream extends ClassTemplateInstantiation {
|
||||
StdBasicIStream() { this.hasQualifiedName(["std", "bsl"], "basic_istream") }
|
||||
}
|
||||
|
||||
private class StdBasicIfStream extends ClassTemplateInstantiation {
|
||||
StdBasicIfStream() { this.hasQualifiedName(["std", "bsl"], "basic_ifstream") }
|
||||
}
|
||||
|
||||
class StdBasicIfStreamConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdBasicIfStreamConstructor() { this.getDeclaringType() instanceof StdBasicIfStream }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
exists(Type t | t = this.getParameter(i).getUnspecifiedType() |
|
||||
t instanceof PointerType and buffer = true
|
||||
or
|
||||
t instanceof ReferenceType and buffer = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class StdBasicIfStreamDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdBasicIfStreamDestructor() { this.getDeclaringType() instanceof StdBasicIfStream }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::istream` function `operator>>` (defined as a member function).
|
||||
*/
|
||||
@@ -542,6 +678,33 @@ private class StdBasicOStream extends ClassTemplateInstantiation {
|
||||
StdBasicOStream() { this.hasQualifiedName(["std", "bsl"], "basic_ostream") }
|
||||
}
|
||||
|
||||
private class StdStringLessThan extends Function, AliasFunction, SideEffectFunction {
|
||||
StdStringLessThan() {
|
||||
this.hasQualifiedName(["std", "bsl"], "operator<") and
|
||||
this.getNumberOfParameters() = 2 and
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
|
||||
StdBasicString and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
|
||||
StdBasicString
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::ostream` functions `operator<<` (defined as a member function),
|
||||
* `put` and `write`.
|
||||
|
||||
@@ -409,6 +409,11 @@ function_defaulted(unique int id: @function ref);
|
||||
|
||||
function_prototyped(unique int id: @function ref)
|
||||
|
||||
deduction_guide_for_class(
|
||||
int id: @function ref,
|
||||
int class_template: @usertype ref
|
||||
)
|
||||
|
||||
member_function_this_type(
|
||||
unique int id: @function ref,
|
||||
int this_type: @type ref
|
||||
@@ -485,10 +490,17 @@ namespace_decls(
|
||||
int bodylocation: @location_default ref
|
||||
);
|
||||
|
||||
case @using.kind of
|
||||
1 = @using_declaration
|
||||
| 2 = @using_directive
|
||||
| 3 = @using_enum_declaration
|
||||
;
|
||||
|
||||
usings(
|
||||
unique int id: @using,
|
||||
int element_id: @element ref,
|
||||
int location: @location_default ref
|
||||
int location: @location_default ref,
|
||||
int kind: int ref
|
||||
);
|
||||
|
||||
/** The element which contains the `using` declaration. */
|
||||
@@ -909,6 +921,11 @@ varspecifiers(
|
||||
int spec_id: @specifier ref
|
||||
);
|
||||
|
||||
explicit_specifier_exprs(
|
||||
unique int func_id: @function ref,
|
||||
int constant: @expr ref
|
||||
)
|
||||
|
||||
attributes(
|
||||
unique int id: @attribute,
|
||||
int kind: int ref,
|
||||
@@ -1358,6 +1375,8 @@ funbind(
|
||||
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
||||
|
||||
/*
|
||||
Binary encoding of the allocator form.
|
||||
|
||||
case @allocator.form of
|
||||
0 = plain
|
||||
| 1 = alignment
|
||||
@@ -1376,11 +1395,13 @@ expr_allocator(
|
||||
);
|
||||
|
||||
/*
|
||||
Binary encoding of the deallocator form.
|
||||
|
||||
case @deallocator.form of
|
||||
0 = plain
|
||||
| 1 = size
|
||||
| 2 = alignment
|
||||
| 3 = size_and_alignment
|
||||
| 4 = destroying_delete
|
||||
;
|
||||
*/
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support destroying deletes
|
||||
compatibility: partial
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Support using-enum declarations.
|
||||
compatibility: partial
|
||||
usings.rel: run usings.qlo
|
||||
@@ -0,0 +1,17 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element target, Location loc, int kind
|
||||
where
|
||||
usings(u, target, loc) and
|
||||
if target instanceof @namespace then kind = 2 else kind = 1
|
||||
select u, target, loc, kind
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add relation between deduction guides and class templates
|
||||
compatibility: partial
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support explicit(bool) specifiers
|
||||
compatibility: partial
|
||||
@@ -1,3 +1,16 @@
|
||||
## 1.2.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed false positives in the `cpp/memory-may-not-be-freed` ("Memory may not be freed") query involving class methods that returned an allocated field of that class being misidentified as allocators.
|
||||
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
|
||||
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
|
||||
* The `cpp/suspicious-allocation-size` ("Not enough memory allocated for array of pointer type") query no longer produces false positives on "variable size" `struct`s.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
@@ -39,7 +39,7 @@ predicate allocCallOrIndirect(Expr e) {
|
||||
allocCallOrIndirect(rtn.getExpr())
|
||||
or
|
||||
// return variable assigned with alloc
|
||||
exists(Variable v |
|
||||
exists(StackVariable v |
|
||||
v = rtn.getExpr().(VariableAccess).getTarget() and
|
||||
allocCallOrIndirect(v.getAnAssignedValue()) and
|
||||
not assignedToFieldOrGlobal(v, _)
|
||||
|
||||
@@ -38,11 +38,18 @@ private string getEofValue() {
|
||||
private predicate checkedForEof(ScanfFunctionCall call) {
|
||||
exists(IRGuardCondition gc |
|
||||
exists(Instruction i | i.getUnconvertedResultExpression() = call |
|
||||
// call == EOF
|
||||
gc.comparesEq(valueNumber(i).getAUse(), getEofValue().toInt(), _, _)
|
||||
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||
// call == EOF
|
||||
val = getEofValue().toInt()
|
||||
or
|
||||
// call == [any positive number]
|
||||
val > 0
|
||||
)
|
||||
or
|
||||
// call < 0 (EOF is guaranteed to be negative)
|
||||
gc.comparesLt(valueNumber(i).getAUse(), 0, true, _)
|
||||
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||
val >= 0
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.models.Models
|
||||
import semmle.code.cpp.commons.Buffer
|
||||
|
||||
predicate baseType(AllocationExpr alloc, Type base) {
|
||||
exists(PointerType pointer |
|
||||
@@ -30,7 +31,8 @@ predicate baseType(AllocationExpr alloc, Type base) {
|
||||
}
|
||||
|
||||
predicate decideOnSize(Type t, int size) {
|
||||
// If the codebase has more than one type with the same name, it can have more than one size.
|
||||
// If the codebase has more than one type with the same name, it can have more than one size. For
|
||||
// most purposes in this query, we use the smallest.
|
||||
size = min(t.getSize())
|
||||
}
|
||||
|
||||
@@ -45,7 +47,8 @@ where
|
||||
size = 0 or
|
||||
(allocated / size) * size = allocated
|
||||
) and
|
||||
not basesize > allocated // covered by SizeCheck.ql
|
||||
not basesize > allocated and // covered by SizeCheck.ql
|
||||
not memberMayBeVarSize(base.getUnspecifiedType(), _) // exclude variable size types
|
||||
select alloc,
|
||||
"Allocated memory (" + allocated.toString() + " bytes) is not a multiple of the size of '" +
|
||||
base.getName() + "' (" + basesize.toString() + " bytes)."
|
||||
|
||||
@@ -10,11 +10,12 @@ contains sensitive data that could somehow be retrieved by an attacker.</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Use alternative platform-supplied functions that will not get optimized away. Examples of such
|
||||
functions include <code>memset_s</code>, <code>SecureZeroMemory</code>, and <code>bzero_explicit</code>.
|
||||
Alternatively, passing the <code>-fno-builtin-memset</code> option to the GCC/Clang compiler usually
|
||||
also prevents the optimization. Finally, you can use the public-domain <code>secure_memzero</code> function
|
||||
(see references below). This function, however, is not guaranteed to work on all platforms and compilers.</p>
|
||||
<p>Use <code>memset_s</code> (from C11) instead of <code>memset</code>, as <code>memset_s</code> will not
|
||||
get optimized away. Alternatively use platform-supplied functions such as <code>SecureZeroMemory</code> or
|
||||
<code>bzero_explicit</code> that make the same guarantee. Passing the <code>-fno-builtin-memset</code>
|
||||
option to the GCC/Clang compiler usually also prevents the optimization. Finally, you can use the
|
||||
public-domain <code>secure_memzero</code> function (see references below). This function, however, is not
|
||||
guaranteed to work on all platforms and compilers.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @id cpp/unsigned-difference-expression-compared-zero
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.8
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @tags security
|
||||
* correctness
|
||||
* external/cwe/cwe-191
|
||||
|
||||
@@ -1,12 +1,31 @@
|
||||
void writeCredentials() {
|
||||
char *password = "cleartext password";
|
||||
FILE* file = fopen("credentials.txt", "w");
|
||||
|
||||
#include <sodium.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void writeCredentialsBad(FILE *file, const char *cleartextCredentials) {
|
||||
// BAD: write password to disk in cleartext
|
||||
fputs(password, file);
|
||||
|
||||
// GOOD: encrypt password first
|
||||
char *encrypted = encrypt(password);
|
||||
fputs(encrypted, file);
|
||||
fputs(cleartextCredentials, file);
|
||||
}
|
||||
|
||||
int writeCredentialsGood(FILE *file, const char *cleartextCredentials, const unsigned char *key, const unsigned char *nonce) {
|
||||
size_t credentialsLen = strlen(cleartextCredentials);
|
||||
size_t ciphertext_len = crypto_secretbox_MACBYTES + credentialsLen;
|
||||
unsigned char *ciphertext = malloc(ciphertext_len);
|
||||
if (!ciphertext) {
|
||||
logError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// encrypt the password first
|
||||
if (crypto_secretbox_easy(ciphertext, (const unsigned char *)cleartextCredentials, credentialsLen, nonce, key) != 0) {
|
||||
free(ciphertext);
|
||||
logError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// GOOD: write encrypted password to disk
|
||||
fwrite(ciphertext, 1, ciphertext_len, file);
|
||||
|
||||
free(ciphertext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,15 +19,20 @@ cleartext.</p>
|
||||
<example>
|
||||
|
||||
<p>The following example shows two ways of storing user credentials in a file. In the 'BAD' case,
|
||||
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
|
||||
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
|
||||
storing them.</p>
|
||||
|
||||
<sample src="CleartextStorage.c" />
|
||||
|
||||
<p>Note that for the 'GOOD' example to work we need to link against an encryption library (in this case libsodium),
|
||||
initialize it with a call to <code>sodium_init</code>, and create the key and nonce with
|
||||
<code>crypto_secretbox_keygen</code> and <code>randombytes_buf</code> respectively. We also need to store those
|
||||
details securely so they can be used for decryption.</p>
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
void bad(void) {
|
||||
char *password = "cleartext password";
|
||||
const char *password = "cleartext password";
|
||||
sqlite3 *credentialsDB;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
@@ -16,14 +16,15 @@ void bad(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void good(void) {
|
||||
char *password = "cleartext password";
|
||||
void good(const char *secretKey) {
|
||||
const char *password = "cleartext password";
|
||||
sqlite3 *credentialsDB;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) {
|
||||
// GOOD: database encryption enabled:
|
||||
sqlite3_exec(credentialsDB, "PRAGMA key = 'secretKey!'", NULL, NULL, NULL);
|
||||
std::string setKeyString = std::string("PRAGMA key = '") + secretKey + "'";
|
||||
sqlite3_exec(credentialsDB, setKeyString.c_str(), NULL, NULL, NULL);
|
||||
sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL);
|
||||
if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);
|
||||
@@ -33,4 +34,3 @@ void good(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,12 @@ In the 'GOOD' case, the database (and thus the credentials) are encrypted.</p>
|
||||
|
||||
<sample src="CleartextSqliteDatabase.c" />
|
||||
|
||||
<p>Note that for the 'GOOD' example to work we need to provide a secret key. Secure key generation and storage is required.</p>
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
|
||||
|
||||
|
||||
@@ -232,6 +232,7 @@ predicate nullCheckInThrowingNew(NewOrNewArrayExpr newExpr, GuardCondition guard
|
||||
from NewOrNewArrayExpr newExpr, Element element, string msg, string elementString
|
||||
where
|
||||
not newExpr.isFromUninstantiatedTemplate(_) and
|
||||
not newExpr.isFromTemplateInstantiation(_) and
|
||||
(
|
||||
noThrowInTryBlock(newExpr, element) and
|
||||
msg = "This allocation cannot throw. $@ is unnecessary." and
|
||||
|
||||
12
cpp/ql/src/change-notes/released/1.2.0.md
Normal file
12
cpp/ql/src/change-notes/released/1.2.0.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## 1.2.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed false positives in the `cpp/memory-may-not-be-freed` ("Memory may not be freed") query involving class methods that returned an allocated field of that class being misidentified as allocators.
|
||||
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
|
||||
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
|
||||
* The `cpp/suspicious-allocation-size` ("Not enough memory allocated for array of pointer type") query no longer produces false positives on "variable size" `struct`s.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.1.0
|
||||
lastReleaseVersion: 1.2.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.1.0
|
||||
version: 1.2.0
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// semmle-extractor-options: -std=c++17
|
||||
// semmle-extractor-options: -std=c++20
|
||||
typedef unsigned long size_t;
|
||||
namespace std {
|
||||
enum class align_val_t : size_t {};
|
||||
|
||||
struct destroying_delete_t {
|
||||
explicit destroying_delete_t() = default;
|
||||
};
|
||||
inline constexpr destroying_delete_t destroying_delete{};
|
||||
}
|
||||
|
||||
void* operator new(size_t, float);
|
||||
@@ -37,6 +42,11 @@ struct SizedDealloc {
|
||||
void operator delete[](void*, size_t);
|
||||
};
|
||||
|
||||
struct DestroyingDealloc {
|
||||
void* operator new(size_t);
|
||||
void operator delete(DestroyingDealloc*, std::destroying_delete_t);
|
||||
};
|
||||
|
||||
struct alignas(128) Overaligned {
|
||||
char a[256];
|
||||
};
|
||||
@@ -59,6 +69,7 @@ void OperatorDelete() {
|
||||
delete static_cast<int*>(nullptr); // No destructor
|
||||
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
||||
delete static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
|
||||
delete static_cast<DestroyingDealloc*>(nullptr); // No destructor, with destroying delete.
|
||||
delete static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
|
||||
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
||||
delete static_cast<const String*>(nullptr); // Pointer to const
|
||||
@@ -103,11 +114,20 @@ struct alignas(128) FailedInitOveraligned {
|
||||
void operator delete[](void*, std::align_val_t, float); // Aligned placement
|
||||
};
|
||||
|
||||
struct alignas(128) FailedInitDestroyingDelete {
|
||||
FailedInitDestroyingDelete();
|
||||
~FailedInitDestroyingDelete();
|
||||
|
||||
void* operator new(size_t); // Non-placement
|
||||
void operator delete(FailedInitDestroyingDelete*, std::destroying_delete_t); // Destroying delete
|
||||
};
|
||||
|
||||
void TestFailedInit(int n) {
|
||||
new FailedInit();
|
||||
new FailedInit[n];
|
||||
new(1.0f) FailedInitOveraligned();
|
||||
new(1.0f) FailedInitOveraligned[10];
|
||||
new FailedInitDestroyingDelete();
|
||||
}
|
||||
|
||||
// --- non-allocating placement new ---
|
||||
|
||||
@@ -1,118 +1,123 @@
|
||||
newExprs
|
||||
| allocators.cpp:49:3:49:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:50:3:50:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
|
||||
| allocators.cpp:51:3:51:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:52:3:52:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
|
||||
| allocators.cpp:53:3:53:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
|
||||
| allocators.cpp:54:3:54:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:55:3:55:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
|
||||
| allocators.cpp:129:3:129:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
|
||||
| allocators.cpp:135:3:135:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
|
||||
| allocators.cpp:59:3:59:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:60:3:60:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
|
||||
| allocators.cpp:61:3:61:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:62:3:62:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
|
||||
| allocators.cpp:63:3:63:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
|
||||
| allocators.cpp:64:3:64:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:65:3:65:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:126:3:126:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
|
||||
| allocators.cpp:128:3:128:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
|
||||
| allocators.cpp:130:3:130:34 | new | FailedInitDestroyingDelete | void* FailedInitDestroyingDelete::operator new(size_t) | 128 | 128 | | |
|
||||
| allocators.cpp:149:3:149:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
|
||||
| allocators.cpp:155:3:155:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
|
||||
newArrayExprs
|
||||
| allocators.cpp:68:3:68:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
|
||||
| allocators.cpp:69:3:69:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
|
||||
| allocators.cpp:70:3:70:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
|
||||
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
|
||||
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
|
||||
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
|
||||
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
|
||||
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
|
||||
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
|
||||
| allocators.cpp:79:3:79:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
|
||||
| allocators.cpp:80:3:80:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
|
||||
| allocators.cpp:81:3:81:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
|
||||
| allocators.cpp:82:3:82:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
|
||||
| allocators.cpp:83:3:83:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
|
||||
| allocators.cpp:127:3:127:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
|
||||
| allocators.cpp:129:3:129:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
|
||||
| allocators.cpp:152:3:152:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
|
||||
| allocators.cpp:156:3:156:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
|
||||
| allocators.cpp:162:13:162:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
|
||||
| allocators.cpp:163:13:163:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
|
||||
| allocators.cpp:164:13:164:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
|
||||
newExprDeallocators
|
||||
| allocators.cpp:52:3:52:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:53:3:53:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
| allocators.cpp:62:3:62:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:63:3:63:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
|
||||
| allocators.cpp:126:3:126:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:128:3:128:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
| allocators.cpp:130:3:130:34 | new | FailedInitDestroyingDelete | void FailedInitDestroyingDelete::operator delete(FailedInitDestroyingDelete*, std::destroying_delete_t) | 128 | 128 | destroying |
|
||||
newArrayExprDeallocators
|
||||
| allocators.cpp:70:3:70:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
| allocators.cpp:81:3:81:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:83:3:83:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:127:3:127:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:129:3:129:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
deleteExprs
|
||||
| allocators.cpp:59:3:59:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized | false |
|
||||
| allocators.cpp:60:3:60:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized | true |
|
||||
| allocators.cpp:62:3:62:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned | false |
|
||||
| allocators.cpp:64:3:64:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
| allocators.cpp:69:3:69:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized | false |
|
||||
| allocators.cpp:70:3:70:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
| allocators.cpp:71:3:71:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized | true |
|
||||
| allocators.cpp:72:3:72:49 | delete | DestroyingDealloc | void DestroyingDealloc::operator delete(DestroyingDealloc*, std::destroying_delete_t) | 1 | 1 | destroying | true |
|
||||
| allocators.cpp:73:3:73:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned | false |
|
||||
| allocators.cpp:75:3:75:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
deleteArrayExprs
|
||||
| allocators.cpp:78:3:78:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:79:3:79:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
|
||||
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:83:3:83:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:89:3:89:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:90:3:90:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:91:3:91:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
|
||||
| allocators.cpp:92:3:92:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:93:3:93:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:94:3:94:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
allocationFunctions
|
||||
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:9:7:9:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:10:7:10:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:121:7:121:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:122:7:122:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:123:7:123:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:124:7:124:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:153:7:153:12 | malloc | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:12:7:12:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:13:7:13:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:14:7:14:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:15:7:15:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:141:7:141:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:142:7:142:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:143:7:143:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:144:7:144:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:173:7:173:12 | malloc | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
allocationExprs
|
||||
| allocators.cpp:49:3:49:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:50:3:50:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:51:3:51:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:52:3:52:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:53:3:53:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:54:3:54:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:55:3:55:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:68:3:68:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:69:3:69:18 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:70:3:70:15 | new[] | getAllocatedElementType = String, getSizeExpr = n, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:71:3:71:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc |
|
||||
| allocators.cpp:72:3:72:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
|
||||
| allocators.cpp:107:3:107:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
|
||||
| allocators.cpp:108:3:108:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:109:3:109:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
|
||||
| allocators.cpp:110:3:110:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
|
||||
| allocators.cpp:129:3:129:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:132:3:132:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:135:3:135:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:136:3:136:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:142:13:142:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
|
||||
| allocators.cpp:143:13:143:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
|
||||
| allocators.cpp:144:13:144:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
|
||||
| allocators.cpp:149:8:149:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:157:50:157:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:158:26:158:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:159:31:159:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:160:16:160:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:161:34:161:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:162:23:162:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:163:3:163:8 | call to malloc | getSizeBytes = 32, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:59:3:59:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:60:3:60:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:61:3:61:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:62:3:62:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:63:3:63:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:64:3:64:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:65:3:65:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:79:3:79:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:80:3:80:18 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:81:3:81:15 | new[] | getAllocatedElementType = String, getSizeExpr = n, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:82:3:82:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc |
|
||||
| allocators.cpp:83:3:83:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
|
||||
| allocators.cpp:126:3:126:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
|
||||
| allocators.cpp:127:3:127:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:128:3:128:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
|
||||
| allocators.cpp:129:3:129:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
|
||||
| allocators.cpp:130:3:130:34 | new | getAllocatedElementType = FailedInitDestroyingDelete, getSizeBytes = 128, requiresDealloc |
|
||||
| allocators.cpp:149:3:149:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:152:3:152:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:155:3:155:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:156:3:156:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:162:13:162:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
|
||||
| allocators.cpp:163:13:163:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
|
||||
| allocators.cpp:164:13:164:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
|
||||
| allocators.cpp:169:8:169:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:177:50:177:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:178:26:178:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:179:31:179:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:180:16:180:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:181:34:181:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:182:23:182:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:183:3:183:8 | call to malloc | getSizeBytes = 32, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
|
||||
deallocationFunctions
|
||||
| allocators.cpp:11:6:11:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:12:6:12:22 | operator delete[] | getFreedArg = 0 |
|
||||
| allocators.cpp:13:6:13:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:14:6:14:22 | operator delete[] | getFreedArg = 0 |
|
||||
| allocators.cpp:16:6:16:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:17:6:17:22 | operator delete[] | getFreedArg = 0 |
|
||||
| allocators.cpp:18:6:18:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:19:6:19:22 | operator delete[] | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
|
||||
deallocationExprs
|
||||
| allocators.cpp:59:3:59:35 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:60:3:60:38 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:61:3:61:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:62:3:62:43 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:63:3:63:47 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:64:3:64:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:78:3:78:37 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:79:3:79:40 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:80:3:80:46 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:81:3:81:45 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:82:3:82:49 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:83:3:83:23 | delete[] | getFreedExpr = call to GetPointer |
|
||||
| allocators.cpp:150:2:150:16 | call to operator delete | getFreedExpr = ptr |
|
||||
| allocators.cpp:69:3:69:35 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:70:3:70:38 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:71:3:71:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:72:3:72:49 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:73:3:73:43 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:74:3:74:47 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:75:3:75:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:89:3:89:37 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:90:3:90:40 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:91:3:91:46 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:92:3:92:45 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:93:3:93:49 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:94:3:94:23 | delete[] | getFreedExpr = call to GetPointer |
|
||||
| allocators.cpp:170:2:170:16 | call to operator delete | getFreedExpr = ptr |
|
||||
|
||||
@@ -50,10 +50,11 @@ query predicate newExprDeallocators(
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
alignment = allocatedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -68,10 +69,11 @@ query predicate newArrayExprDeallocators(
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -87,10 +89,11 @@ query predicate deleteExprs(
|
||||
type = deletedType.toString() and
|
||||
size = deletedType.getSize() and
|
||||
alignment = deletedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
) and
|
||||
if exists(expr.getDeallocatorCall())
|
||||
then hasDeallocatorCall = true
|
||||
@@ -108,10 +111,11 @@ query predicate deleteArrayExprs(
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
| declspec.cpp:4:23:4:43 | Use fatal() instead | declspec.cpp:4:59:4:62 | exit | declspec.cpp:4:12:4:21 | deprecated | Use fatal() instead |
|
||||
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
|
||||
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
|
||||
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
|
||||
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
|
||||
| routine_attributes.c:3:53:3:59 | dummy | routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref | dummy |
|
||||
| routine_attributes.c:4:62:4:68 | dummy | routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:55:4:59 | alias | dummy |
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllexport |
|
||||
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllimport |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
|
||||
| routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref |
|
||||
| routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:46:4:52 | weakref |
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility | type_attributes2.cpp:5:7:5:12 | hidden |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
|
||||
| type_attributes_ms.cpp:4:67:4:75 | IDispatch | type_attributes_ms.cpp:4:19:4:22 | uuid | type_attributes_ms.cpp:4:24:4:63 | {00020400-0000-0000-c000-000000000046} |
|
||||
| type_attributes_ms.cpp:5:30:5:33 | Str1 | type_attributes_ms.cpp:5:12:5:16 | align | type_attributes_ms.cpp:5:18:5:19 | 32 |
|
||||
| type_attributes_ms.cpp:6:55:6:62 | IUnknown | type_attributes_ms.cpp:6:2:6:2 | uuid | type_attributes_ms.cpp:6:2:6:2 | 00000000-0000-0000-c000-000000000046 |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
|
||||
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
|
||||
| type_attributes.c:10:54:10:54 | (unnamed class/struct/union) | type_attributes.c:10:30:10:50 | transparent_union |
|
||||
| type_attributes.c:16:54:16:54 | (unnamed class/struct/union) | type_attributes.c:16:30:16:50 | transparent_union |
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
| ms_var_attributes.cpp:20:34:20:37 | pBuf | ms_var_attributes.cpp:20:12:20:12 | SAL_volatile |
|
||||
| ms_var_attributes.h:5:22:5:27 | myInt3 | ms_var_attributes.h:5:1:5:9 | dllexport |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
|
||||
| var_attributes.c:1:12:1:19 | weak_var | var_attributes.c:1:36:1:39 | weak |
|
||||
| var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref |
|
||||
|
||||
@@ -11,14 +11,14 @@ edges
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
|
||||
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:2 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | Src:MaD:0 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:1 |
|
||||
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:644 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | Src:MaD:642 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:13:18:13:18 | x | provenance | |
|
||||
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:13:10:13:16 | call to ymlStep | provenance | |
|
||||
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:1 |
|
||||
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
|
||||
| test.cpp:13:18:13:18 | x | test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | provenance | |
|
||||
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:2 |
|
||||
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:644 |
|
||||
nodes
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | semmle.label | [summary param] *0 in buffer |
|
||||
| asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | semmle.label | [summary] to write: ReturnValue in buffer |
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
| Dubious signature "(const_iterator,size_type,const T &)" in summary model. |
|
||||
| Dubious signature "(deque &&)" in summary model. |
|
||||
| Dubious signature "(deque &&,const Allocator &)" in summary model. |
|
||||
| Dubious signature "(format_string,Args &&)" in summary model. |
|
||||
| Dubious signature "(forward_list &&)" in summary model. |
|
||||
| Dubious signature "(forward_list &&,const Allocator &)" in summary model. |
|
||||
| Dubious signature "(list &&)" in summary model. |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
#include "stl.h"
|
||||
typedef unsigned long size_t;
|
||||
typedef struct {} FILE;
|
||||
|
||||
@@ -157,3 +157,11 @@ void test2()
|
||||
sink(s[strlen(s) - 1]); // $ ast,ir
|
||||
sink(ws + (wcslen(ws) / 2)); // $ ast,ir
|
||||
}
|
||||
|
||||
void test_format() {
|
||||
auto s = std::format("{}", string::source());
|
||||
sink(s); // $ ir MISSING: ast
|
||||
|
||||
auto s2 = std::format(string::source());
|
||||
sink(s2); // $ ir MISSING: ast
|
||||
}
|
||||
@@ -447,6 +447,10 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
|
||||
| format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT |
|
||||
| format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT |
|
||||
| format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT |
|
||||
| format.cpp:162:12:162:22 | call to format | format.cpp:163:8:163:8 | s | |
|
||||
| format.cpp:162:24:162:27 | {} | format.cpp:162:24:162:27 | call to basic_format_string | TAINT |
|
||||
| format.cpp:165:13:165:23 | call to format | format.cpp:166:8:166:9 | s2 | |
|
||||
| format.cpp:165:25:165:38 | call to source | format.cpp:165:25:165:40 | call to basic_format_string | TAINT |
|
||||
| map.cpp:21:28:21:28 | call to pair | map.cpp:23:2:23:2 | a | |
|
||||
| map.cpp:21:28:21:28 | call to pair | map.cpp:24:7:24:7 | a | |
|
||||
| map.cpp:21:28:21:28 | call to pair | map.cpp:25:7:25:7 | a | |
|
||||
|
||||
@@ -642,3 +642,38 @@ namespace std {
|
||||
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
|
||||
};
|
||||
}
|
||||
|
||||
// --- string view ---
|
||||
|
||||
namespace std {
|
||||
template<class CharT, class Traits = char_traits<CharT>>
|
||||
class basic_string_view {
|
||||
public:
|
||||
using size_type = size_t;
|
||||
|
||||
basic_string_view() noexcept;
|
||||
basic_string_view(const basic_string_view&) noexcept;
|
||||
basic_string_view(const CharT*, size_type);
|
||||
basic_string_view(const CharT*);
|
||||
template<class It, class End> basic_string_view(It, End);
|
||||
template<class R> explicit basic_string_view(R&&);
|
||||
basic_string_view& operator=(const basic_string_view&) noexcept;
|
||||
};
|
||||
|
||||
using string_view = basic_string_view<char>;
|
||||
}
|
||||
|
||||
// --- format ---
|
||||
namespace std {
|
||||
template<class CharT /* class... Args */>
|
||||
struct basic_format_string {
|
||||
public:
|
||||
template<class T> basic_format_string(const T&);
|
||||
|
||||
basic_string_view<CharT> get() const noexcept;
|
||||
};
|
||||
|
||||
using format_string = basic_format_string<char>; // simplified from `char, std::type_identity_t<Args>...`
|
||||
|
||||
template<class... Args> string format( format_string fmt, Args&&... args );
|
||||
}
|
||||
@@ -27,6 +27,10 @@ signatureMatches
|
||||
| stl.h:190:17:190:23 | replace | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 0 |
|
||||
| stl.h:190:17:190:23 | replace | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 1 |
|
||||
| stl.h:190:17:190:23 | replace | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
|
||||
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | deque | insert<InputIt> | 2 |
|
||||
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | forward_list | insert_after<InputIt> | 2 |
|
||||
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | list | insert<InputIt> | 2 |
|
||||
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
|
||||
| stl.h:294:12:294:17 | vector | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
|
||||
| stl.h:294:12:294:17 | vector | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
|
||||
| stl.h:294:12:294:17 | vector | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
|
||||
@@ -175,6 +179,7 @@ signatureMatches
|
||||
| stl.h:333:42:333:47 | insert | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 1 |
|
||||
| stl.h:333:42:333:47 | insert | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
|
||||
| stl.h:333:42:333:47 | insert | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
|
||||
| stl.h:335:37:335:43 | emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:396:3:396:3 | pair | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
|
||||
| stl.h:396:3:396:3 | pair | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
|
||||
| stl.h:396:3:396:3 | pair | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
|
||||
@@ -215,6 +220,19 @@ signatureMatches
|
||||
| stl.h:396:3:396:3 | pair | (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 |
|
||||
| stl.h:396:3:396:3 | pair | (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 |
|
||||
| stl.h:396:3:396:3 | pair | (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 |
|
||||
| stl.h:440:36:440:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:440:36:440:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:448:48:448:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:448:48:448:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:452:42:452:57 | insert_or_assign | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:508:36:508:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:508:36:508:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:520:42:520:57 | insert_or_assign | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | deque | assign<InputIt> | 0 |
|
||||
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | deque | assign<InputIt> | 1 |
|
||||
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | forward_list | assign<InputIt> | 0 |
|
||||
@@ -223,6 +241,8 @@ signatureMatches
|
||||
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | list | assign<InputIt> | 1 |
|
||||
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | vector | assign<InputIt> | 0 |
|
||||
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | vector | assign<InputIt> | 1 |
|
||||
| stl.h:569:36:569:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:569:36:569:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 0 |
|
||||
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 1 |
|
||||
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | forward_list | assign<InputIt> | 0 |
|
||||
@@ -231,6 +251,8 @@ signatureMatches
|
||||
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | list | assign<InputIt> | 1 |
|
||||
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 0 |
|
||||
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 1 |
|
||||
| stl.h:623:36:623:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:623:36:623:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 0 |
|
||||
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 1 |
|
||||
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | forward_list | assign<InputIt> | 0 |
|
||||
@@ -239,6 +261,10 @@ signatureMatches
|
||||
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | list | assign<InputIt> | 1 |
|
||||
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 0 |
|
||||
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 1 |
|
||||
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 0 |
|
||||
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 0 |
|
||||
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 1 |
|
||||
getSignatureParameterName
|
||||
| (InputIt,InputIt) | deque | assign<InputIt> | 0 | func:0 |
|
||||
| (InputIt,InputIt) | deque | assign<InputIt> | 1 | func:0 |
|
||||
@@ -315,6 +341,8 @@ getSignatureParameterName
|
||||
| (deque &&) | deque | deque | 0 | deque && |
|
||||
| (deque &&,const Allocator &) | deque<T,Allocator> | deque | 0 | deque && |
|
||||
| (deque &&,const Allocator &) | deque<T,Allocator> | deque | 1 | const class:1 & |
|
||||
| (format_string,Args &&) | | format<Args> | 0 | format_string |
|
||||
| (format_string,Args &&) | | format<Args> | 1 | func:0 && |
|
||||
| (forward_list &&) | forward_list | forward_list | 0 | forward_list && |
|
||||
| (forward_list &&,const Allocator &) | forward_list<T,Allocator> | forward_list | 0 | forward_list && |
|
||||
| (forward_list &&,const Allocator &) | forward_list<T,Allocator> | forward_list | 1 | const class:1 & |
|
||||
@@ -345,6 +373,14 @@ getSignatureParameterName
|
||||
| (vector &&,const Allocator &) | vector<T,Allocator> | vector | 0 | vector && |
|
||||
| (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 | const class:1 & |
|
||||
getParameterTypeName
|
||||
| smart_pointer.cpp:7:27:7:30 | sink | 0 | shared_ptr & |
|
||||
| smart_pointer.cpp:7:27:7:30 | sink | 0 | shared_ptr & |
|
||||
| smart_pointer.cpp:8:27:8:30 | sink | 0 | unique_ptr & |
|
||||
| smart_pointer.cpp:8:27:8:30 | sink | 0 | unique_ptr & |
|
||||
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
|
||||
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
|
||||
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
|
||||
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
|
||||
| stl.h:49:3:49:10 | iterator | 0 | const iterator & |
|
||||
| stl.h:49:3:49:10 | iterator | 0 | const iterator & |
|
||||
| stl.h:49:3:49:10 | iterator | 0 | const iterator & |
|
||||
@@ -377,6 +413,8 @@ getParameterTypeName
|
||||
| stl.h:88:25:88:33 | operator= | 0 | value_type && |
|
||||
| stl.h:91:24:91:33 | operator++ | 0 | int |
|
||||
| stl.h:91:24:91:33 | operator++ | 0 | int |
|
||||
| stl.h:95:44:95:44 | back_inserter | 0 | func:0 & |
|
||||
| stl.h:95:44:95:44 | back_inserter | 0 | func:0 & |
|
||||
| stl.h:148:3:148:14 | basic_string | 0 | const class:2 & |
|
||||
| stl.h:149:33:149:44 | basic_string | 0 | const class:0 * |
|
||||
| stl.h:149:33:149:44 | basic_string | 1 | const class:2 & |
|
||||
@@ -425,6 +463,10 @@ getParameterTypeName
|
||||
| stl.h:193:8:193:12 | clear | 2 | size_type |
|
||||
| stl.h:195:8:195:11 | swap | 0 | size_type |
|
||||
| stl.h:195:8:195:11 | swap | 1 | size_type |
|
||||
| stl.h:198:94:198:102 | operator+ | 0 | const basic_string & |
|
||||
| stl.h:198:94:198:102 | operator+ | 1 | const basic_string & |
|
||||
| stl.h:199:94:199:102 | operator+ | 0 | const basic_string & |
|
||||
| stl.h:199:94:199:102 | operator+ | 1 | const func:0 * |
|
||||
| stl.h:214:33:214:42 | operator>> | 0 | int & |
|
||||
| stl.h:217:33:217:35 | get | 0 | char_type & |
|
||||
| stl.h:218:33:218:35 | get | 0 | char_type * |
|
||||
@@ -439,10 +481,23 @@ getParameterTypeName
|
||||
| stl.h:226:32:226:38 | getline | 0 | char_type * |
|
||||
| stl.h:226:32:226:38 | getline | 1 | streamsize |
|
||||
| stl.h:226:32:226:38 | getline | 2 | char_type |
|
||||
| stl.h:229:68:229:77 | operator>> | 0 | basic_istream & |
|
||||
| stl.h:229:68:229:77 | operator>> | 1 | func:0 * |
|
||||
| stl.h:230:85:230:94 | operator>> | 0 | basic_istream & |
|
||||
| stl.h:230:85:230:94 | operator>> | 1 | basic_string & |
|
||||
| stl.h:232:84:232:90 | getline | 0 | basic_istream & |
|
||||
| stl.h:232:84:232:90 | getline | 1 | basic_string & |
|
||||
| stl.h:232:84:232:90 | getline | 2 | func:0 |
|
||||
| stl.h:233:84:233:90 | getline | 0 | basic_istream & |
|
||||
| stl.h:233:84:233:90 | getline | 1 | basic_string & |
|
||||
| stl.h:240:33:240:42 | operator<< | 0 | int |
|
||||
| stl.h:242:33:242:35 | put | 0 | char_type |
|
||||
| stl.h:243:33:243:37 | write | 0 | const char_type * |
|
||||
| stl.h:243:33:243:37 | write | 1 | streamsize |
|
||||
| stl.h:247:67:247:76 | operator<< | 0 | basic_ostream & |
|
||||
| stl.h:247:67:247:76 | operator<< | 1 | const func:0 * |
|
||||
| stl.h:248:85:248:94 | operator<< | 0 | basic_ostream & |
|
||||
| stl.h:248:85:248:94 | operator<< | 1 | const basic_string & |
|
||||
| stl.h:259:12:259:29 | basic_stringstream | 0 | const basic_string & |
|
||||
| stl.h:263:23:263:31 | operator= | 0 | basic_stringstream && |
|
||||
| stl.h:265:8:265:11 | swap | 0 | basic_stringstream & |
|
||||
@@ -496,11 +551,20 @@ getParameterTypeName
|
||||
| stl.h:333:42:333:47 | insert | 1 | func:0 |
|
||||
| stl.h:333:42:333:47 | insert | 2 | func:0 |
|
||||
| stl.h:333:42:333:47 | insert | 2 | func:0 |
|
||||
| stl.h:335:37:335:43 | emplace | 0 | const_iterator |
|
||||
| stl.h:335:37:335:43 | emplace | 1 | func:0 && |
|
||||
| stl.h:336:33:336:44 | emplace_back | 0 | func:0 && |
|
||||
| stl.h:338:8:338:11 | swap | 0 | vector & |
|
||||
| stl.h:351:12:351:21 | shared_ptr | 0 | class:0 * |
|
||||
| stl.h:352:3:352:12 | shared_ptr | 0 | const shared_ptr & |
|
||||
| stl.h:352:3:352:12 | shared_ptr | 0 | const shared_ptr & |
|
||||
| stl.h:369:12:369:21 | unique_ptr | 0 | class:0 * |
|
||||
| stl.h:380:52:380:62 | make_unique | 0 | func:1 && |
|
||||
| stl.h:380:52:380:62 | make_unique | 0 | func:1 && |
|
||||
| stl.h:380:52:380:62 | make_unique | 0 | func:1 && |
|
||||
| stl.h:382:52:382:62 | make_shared | 0 | func:1 && |
|
||||
| stl.h:382:52:382:62 | make_shared | 0 | func:1 && |
|
||||
| stl.h:382:52:382:62 | make_shared | 0 | func:1 && |
|
||||
| stl.h:396:3:396:3 | pair | 0 | const class:0 & |
|
||||
| stl.h:396:3:396:3 | pair | 0 | const class:0 & |
|
||||
| stl.h:396:3:396:3 | pair | 0 | const class:0 & |
|
||||
@@ -524,14 +588,42 @@ getParameterTypeName
|
||||
| stl.h:397:30:397:33 | pair | 0 | const pair & |
|
||||
| stl.h:397:30:397:33 | pair | 0 | const pair & |
|
||||
| stl.h:399:8:399:11 | swap | 0 | pair & |
|
||||
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
|
||||
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
|
||||
| stl.h:422:3:422:5 | map | 0 | const map & |
|
||||
| stl.h:426:8:426:16 | operator= | 0 | const map & |
|
||||
| stl.h:435:6:435:15 | operator[] | 0 | key_type && |
|
||||
| stl.h:435:6:435:15 | operator[] | 0 | key_type && |
|
||||
| stl.h:436:6:436:7 | at | 0 | const key_type & |
|
||||
| stl.h:439:48:439:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:439:48:439:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:440:36:440:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:440:36:440:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:440:36:440:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:440:36:440:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:443:24:443:29 | insert | 0 | value_type && |
|
||||
| stl.h:445:12:445:17 | insert | 0 | const_iterator |
|
||||
| stl.h:445:12:445:17 | insert | 1 | value_type && |
|
||||
| stl.h:448:48:448:58 | try_emplace | 0 | key_type && |
|
||||
| stl.h:448:48:448:58 | try_emplace | 0 | key_type && |
|
||||
| stl.h:448:48:448:58 | try_emplace | 1 | func:0 && |
|
||||
| stl.h:448:48:448:58 | try_emplace | 1 | func:0 && |
|
||||
| stl.h:450:36:450:46 | try_emplace | 0 | const_iterator |
|
||||
| stl.h:450:36:450:46 | try_emplace | 0 | const_iterator |
|
||||
| stl.h:450:36:450:46 | try_emplace | 1 | key_type && |
|
||||
| stl.h:450:36:450:46 | try_emplace | 1 | key_type && |
|
||||
| stl.h:450:36:450:46 | try_emplace | 2 | func:0 && |
|
||||
| stl.h:450:36:450:46 | try_emplace | 2 | func:0 && |
|
||||
| stl.h:452:42:452:57 | insert_or_assign | 0 | key_type && |
|
||||
| stl.h:452:42:452:57 | insert_or_assign | 1 | func:0 && |
|
||||
| stl.h:454:30:454:45 | insert_or_assign | 0 | const_iterator |
|
||||
@@ -550,9 +642,34 @@ getParameterTypeName
|
||||
| stl.h:503:16:503:25 | operator[] | 0 | key_type && |
|
||||
| stl.h:503:16:503:25 | operator[] | 0 | key_type && |
|
||||
| stl.h:504:16:504:17 | at | 0 | const key_type & |
|
||||
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:508:36:508:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:508:36:508:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:508:36:508:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:508:36:508:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:511:24:511:29 | insert | 0 | value_type && |
|
||||
| stl.h:513:12:513:17 | insert | 0 | const_iterator |
|
||||
| stl.h:513:12:513:17 | insert | 1 | value_type && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
|
||||
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
|
||||
| stl.h:518:36:518:46 | try_emplace | 0 | const_iterator |
|
||||
| stl.h:518:36:518:46 | try_emplace | 0 | const_iterator |
|
||||
| stl.h:518:36:518:46 | try_emplace | 1 | key_type && |
|
||||
| stl.h:518:36:518:46 | try_emplace | 1 | key_type && |
|
||||
| stl.h:518:36:518:46 | try_emplace | 2 | func:0 && |
|
||||
| stl.h:518:36:518:46 | try_emplace | 2 | func:0 && |
|
||||
| stl.h:520:42:520:57 | insert_or_assign | 0 | key_type && |
|
||||
| stl.h:520:42:520:57 | insert_or_assign | 1 | func:0 && |
|
||||
| stl.h:522:30:522:45 | insert_or_assign | 0 | const_iterator |
|
||||
@@ -567,6 +684,12 @@ getParameterTypeName
|
||||
| stl.h:557:33:557:35 | set | 0 | func:0 |
|
||||
| stl.h:557:33:557:35 | set | 1 | func:0 |
|
||||
| stl.h:560:8:560:16 | operator= | 0 | const set & |
|
||||
| stl.h:568:48:568:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:568:48:568:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:569:36:569:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:569:36:569:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:569:36:569:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:569:36:569:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:571:23:571:28 | insert | 0 | value_type && |
|
||||
| stl.h:573:12:573:17 | insert | 0 | const_iterator |
|
||||
| stl.h:573:12:573:17 | insert | 1 | value_type && |
|
||||
@@ -584,6 +707,12 @@ getParameterTypeName
|
||||
| stl.h:611:33:611:45 | unordered_set | 1 | func:0 |
|
||||
| stl.h:611:33:611:45 | unordered_set | 2 | size_type |
|
||||
| stl.h:614:18:614:26 | operator= | 0 | const unordered_set & |
|
||||
| stl.h:622:48:622:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:622:48:622:54 | emplace | 0 | func:0 && |
|
||||
| stl.h:623:36:623:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:623:36:623:47 | emplace_hint | 0 | const_iterator |
|
||||
| stl.h:623:36:623:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:623:36:623:47 | emplace_hint | 1 | func:0 && |
|
||||
| stl.h:625:24:625:29 | insert | 0 | value_type && |
|
||||
| stl.h:627:12:627:17 | insert | 0 | const_iterator |
|
||||
| stl.h:627:12:627:17 | insert | 1 | value_type && |
|
||||
@@ -594,3 +723,18 @@ getParameterTypeName
|
||||
| stl.h:636:37:636:41 | merge | 0 | unordered_set & |
|
||||
| stl.h:639:12:639:15 | find | 0 | const key_type & |
|
||||
| stl.h:641:28:641:38 | equal_range | 0 | const key_type & |
|
||||
| stl.h:671:21:671:39 | basic_format_string | 0 | const func:0 & |
|
||||
| stl.h:671:21:671:39 | basic_format_string | 0 | const func:0 & |
|
||||
| stl.h:678:33:678:38 | format | 0 | format_string |
|
||||
| stl.h:678:33:678:38 | format | 0 | format_string |
|
||||
| stl.h:678:33:678:38 | format | 1 | func:0 && |
|
||||
| stl.h:678:33:678:38 | format | 1 | func:0 && |
|
||||
| stringstream.cpp:18:6:18:9 | sink | 0 | const basic_ostream> & |
|
||||
| stringstream.cpp:21:6:21:9 | sink | 0 | const basic_istream> & |
|
||||
| stringstream.cpp:24:6:24:9 | sink | 0 | const basic_iostream> & |
|
||||
| swap1.cpp:14:9:14:9 | move | 0 | func:0 & |
|
||||
| swap2.cpp:14:9:14:9 | move | 0 | func:0 & |
|
||||
| swap.h:4:20:4:23 | swap | 0 | func:0 & |
|
||||
| swap.h:4:20:4:23 | swap | 1 | func:0 & |
|
||||
| vector.cpp:14:27:14:30 | sink | 0 | vector> & |
|
||||
| vector.cpp:14:27:14:30 | sink | 0 | vector> & |
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from DeductionGuide d
|
||||
where not exists(d.getTemplateClass())
|
||||
select d
|
||||
@@ -0,0 +1,5 @@
|
||||
| file://:0:0:0:0 | C | test.cpp:4:8:4:8 | C<T> |
|
||||
| file://:0:0:0:0 | C | test.cpp:4:8:4:8 | C<T> |
|
||||
| test.cpp:5:5:5:5 | (unnamed deduction guide) | test.cpp:4:8:4:8 | C<T> |
|
||||
| test.cpp:6:5:6:5 | (unnamed deduction guide) | test.cpp:4:8:4:8 | C<T> |
|
||||
| test.cpp:12:1:12:1 | C | test.cpp:4:8:4:8 | C<T> |
|
||||
@@ -0,0 +1,4 @@
|
||||
import cpp
|
||||
|
||||
from DeductionGuide d
|
||||
select d, d.getTemplateClass()
|
||||
21
cpp/ql/test/library-tests/deduction_guides/test.cpp
Normal file
21
cpp/ql/test/library-tests/deduction_guides/test.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// semmle-extractor-options: -std=c++20
|
||||
|
||||
template<typename T>
|
||||
struct C {
|
||||
C(const T);
|
||||
C(char, char);
|
||||
};
|
||||
|
||||
C(const double) -> C<int>;
|
||||
|
||||
template<typename T>
|
||||
C(const T) -> C<int>;
|
||||
|
||||
C(char, char) -> C<char>;
|
||||
|
||||
void test() {
|
||||
new C<char>(0);
|
||||
new C<int>(0);
|
||||
new C(0.0f);
|
||||
new C(0.0);
|
||||
}
|
||||
@@ -62,3 +62,9 @@ Virtual getAVirtual();
|
||||
void test9() {
|
||||
typeid(getAVirtual()); // unevaluated
|
||||
}
|
||||
|
||||
void constExprIf() {
|
||||
if constexpr(sizeof(int) == 4) { } // unevaluated
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20
|
||||
@@ -14,3 +14,7 @@
|
||||
| test.cpp:57:9:57:9 | 4 |
|
||||
| test.cpp:63:9:63:19 | call to getAVirtual |
|
||||
| test.cpp:63:9:63:21 | temporary object |
|
||||
| test.cpp:67:16:67:26 | sizeof(int) |
|
||||
| test.cpp:67:16:67:31 | ... == ... |
|
||||
| test.cpp:67:31:67:31 | 4 |
|
||||
| test.cpp:67:31:67:31 | (unsigned long)... |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ missingOperand
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
| ir.cpp:2670:3:2670:9 | Phi: call to use_int | Instruction 'Phi: call to use_int' is missing an operand for predecessor block 'EnterFunction: phi_with_single_input_at_merge' in function '$@'. | ir.cpp:2663:13:2663:42 | void phi_with_single_input_at_merge(bool) | void phi_with_single_input_at_merge(bool) |
|
||||
missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user