mirror of
https://github.com/github/codeql.git
synced 2026-07-07 20:45:28 +02:00
Compare commits
149 Commits
codeql-cli
...
changedocs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cf5d4178f | ||
|
|
d23d138e7d | ||
|
|
e1329dff72 | ||
|
|
b6aea3cde1 | ||
|
|
d189526283 | ||
|
|
707acdef08 | ||
|
|
450137d2cf | ||
|
|
0ba5a74f6a | ||
|
|
8eb3b31ee2 | ||
|
|
72e05c952e | ||
|
|
c0263bef5a | ||
|
|
6b68cf6bdc | ||
|
|
06a3bf8808 | ||
|
|
822f8b06f0 | ||
|
|
a944922c97 | ||
|
|
c051d33cc7 | ||
|
|
52020f7e5b | ||
|
|
91edf82c8a | ||
|
|
b640bdccdc | ||
|
|
52f8f04e9d | ||
|
|
91f5f086fb | ||
|
|
d2f5734ac5 | ||
|
|
30abc958a8 | ||
|
|
eea3e82cca | ||
|
|
27314aac16 | ||
|
|
9d75782c44 | ||
|
|
087b0dac1d | ||
|
|
9fb657c4c4 | ||
|
|
4d3377b116 | ||
|
|
3e7a60c1a6 | ||
|
|
c693f03462 | ||
|
|
245f43dd58 | ||
|
|
099c282277 | ||
|
|
7a48fe1102 | ||
|
|
c5da43e691 | ||
|
|
34ad211900 | ||
|
|
032ae9e1e7 | ||
|
|
5a39610ba7 | ||
|
|
5854e88f63 | ||
|
|
d77d7c533b | ||
|
|
ecefa3e383 | ||
|
|
3f5b4a81cf | ||
|
|
44e33c7be7 | ||
|
|
d8cc92068a | ||
|
|
4a34dc125b | ||
|
|
b3bffb6826 | ||
|
|
7ec3162583 | ||
|
|
a5efe9fa09 | ||
|
|
90b25a6696 | ||
|
|
5e484e4006 | ||
|
|
b1bea31720 | ||
|
|
28cff2ea20 | ||
|
|
1de91b4cd5 | ||
|
|
ff60d9647f | ||
|
|
ec134927d8 | ||
|
|
9f79a39deb | ||
|
|
854a277ab5 | ||
|
|
b7542ee575 | ||
|
|
eaf2949857 | ||
|
|
741a3289a1 | ||
|
|
4cbc3349f6 | ||
|
|
acbca9c108 | ||
|
|
3edeb82d5b | ||
|
|
89f958105a | ||
|
|
1456012b54 | ||
|
|
4920039a00 | ||
|
|
a98fac0d7d | ||
|
|
6026f65f8b | ||
|
|
43df4a9393 | ||
|
|
c3f2faff76 | ||
|
|
a9f6b2110e | ||
|
|
4c8da54b64 | ||
|
|
67dac96e80 | ||
|
|
e467cc033e | ||
|
|
1ed5af1d6a | ||
|
|
db53be39fe | ||
|
|
37ceb0118a | ||
|
|
e461691c85 | ||
|
|
5e6c9fb661 | ||
|
|
5a5c5d1012 | ||
|
|
29bda5a805 | ||
|
|
c1bd892a13 | ||
|
|
4f80ae2190 | ||
|
|
092de640fe | ||
|
|
ff8bb2b1f8 | ||
|
|
d2573310c6 | ||
|
|
b5b9c4d931 | ||
|
|
bb86a07a93 | ||
|
|
5912a17ab4 | ||
|
|
49cc8f8ff8 | ||
|
|
8038796207 | ||
|
|
3defc8b5de | ||
|
|
437c679266 | ||
|
|
af562f15f3 | ||
|
|
e8718f9d2f | ||
|
|
7b03f3268f | ||
|
|
06a9599906 | ||
|
|
11f5663afc | ||
|
|
a0954f15c0 | ||
|
|
45e92cec6a | ||
|
|
2ad70cbee2 | ||
|
|
db9cd1f612 | ||
|
|
b1608d815b | ||
|
|
b4fa23d731 | ||
|
|
c256c87a7e | ||
|
|
281212a22c | ||
|
|
999fb07931 | ||
|
|
8262330e4d | ||
|
|
b00e312569 | ||
|
|
f931dab14a | ||
|
|
ffc61ae1bb | ||
|
|
6d468c1bae | ||
|
|
4790656b79 | ||
|
|
2a5144d9d9 | ||
|
|
a64eafca2b | ||
|
|
ad4bca9975 | ||
|
|
0990a370c7 | ||
|
|
9713551448 | ||
|
|
4fa45bb81c | ||
|
|
62944ee473 | ||
|
|
3bd330423d | ||
|
|
94078e851c | ||
|
|
7b8301ac7a | ||
|
|
1c8e0c453c | ||
|
|
5f70c44270 | ||
|
|
9dd43d8e6f | ||
|
|
d4bfab4735 | ||
|
|
b83147fa44 | ||
|
|
8241d0b7ef | ||
|
|
07a25a233d | ||
|
|
64432215a9 | ||
|
|
8526510783 | ||
|
|
173cd13ded | ||
|
|
60b9d19d72 | ||
|
|
8458bde51e | ||
|
|
9e25279cb8 | ||
|
|
162245fb9a | ||
|
|
059ef42f41 | ||
|
|
878867205e | ||
|
|
91db2b6c9c | ||
|
|
51f3f15e42 | ||
|
|
d79a253c20 | ||
|
|
7380e29774 | ||
|
|
d994959720 | ||
|
|
81ec6861f9 | ||
|
|
f217de9623 | ||
|
|
6a46fb54c5 | ||
|
|
f017821062 | ||
|
|
d4203d9286 |
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
|
||||||
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
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: feature
|
||||||
|
---
|
||||||
|
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* 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.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* 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.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 1.3.0
|
version: 1.3.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
|
|||||||
* A C++ `using` directive or `using` declaration.
|
* A C++ `using` directive or `using` declaration.
|
||||||
*/
|
*/
|
||||||
class UsingEntry extends Locatable, @using {
|
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 {
|
class UsingDeclarationEntry extends UsingEntry {
|
||||||
UsingDeclarationEntry() {
|
UsingDeclarationEntry() { usings(underlyingElement(this), _, _, 1) }
|
||||||
not exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the declaration that is referenced by this using declaration. For
|
* Gets the declaration that is referenced by this using declaration. For
|
||||||
* example, `std::string` in `using std::string`.
|
* 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() }
|
override string toString() { result = "using " + this.getDeclaration().getDescription() }
|
||||||
}
|
}
|
||||||
@@ -186,19 +184,36 @@ class UsingDeclarationEntry extends UsingEntry {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class UsingDirectiveEntry extends UsingEntry {
|
class UsingDirectiveEntry extends UsingEntry {
|
||||||
UsingDirectiveEntry() {
|
UsingDirectiveEntry() { usings(underlyingElement(this), _, _, 2) }
|
||||||
exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the namespace that is referenced by this using directive. For
|
* Gets the namespace that is referenced by this using directive. For
|
||||||
* example, `std` in `using namespace std`.
|
* 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() }
|
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
|
* Holds if `g` is an instance of `GlobalNamespace`. This predicate
|
||||||
* is used suppress a warning in `GlobalNamespace.getADeclaration()`
|
* is used suppress a warning in `GlobalNamespace.getADeclaration()`
|
||||||
|
|||||||
@@ -215,19 +215,16 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
|||||||
predicate localMustFlowStep(Node node1, Node node2) { none() }
|
predicate localMustFlowStep(Node node1, Node node2) { none() }
|
||||||
|
|
||||||
/** Gets the type of `n` used for type pruning. */
|
/** Gets the type of `n` used for type pruning. */
|
||||||
Type getNodeType(Node n) {
|
DataFlowType getNodeType(Node n) {
|
||||||
exists(n) and
|
exists(n) and
|
||||||
result instanceof VoidType // stub implementation
|
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
|
* 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`.
|
* 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
|
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +240,11 @@ class DataFlowCallable extends Function { }
|
|||||||
|
|
||||||
class DataFlowExpr = Expr;
|
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. */
|
/** A function call relevant for data flow. */
|
||||||
class DataFlowCall extends Expr instanceof Call {
|
class DataFlowCall extends Expr instanceof Call {
|
||||||
|
|||||||
@@ -855,6 +855,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.
|
* Gets the type that is being allocated.
|
||||||
*
|
*
|
||||||
@@ -1025,6 +1035,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.
|
* Gets the object or array being deleted.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -994,9 +994,6 @@ DataFlowType getNodeType(Node n) {
|
|||||||
result instanceof VoidType // stub implementation
|
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
|
* 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`.
|
* a node of type `t1` to a node of type `t2`.
|
||||||
@@ -1097,7 +1094,11 @@ class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
|
|||||||
|
|
||||||
class DataFlowExpr = Expr;
|
class DataFlowExpr = Expr;
|
||||||
|
|
||||||
class DataFlowType = Type;
|
final private class TypeFinal = Type;
|
||||||
|
|
||||||
|
class DataFlowType extends TypeFinal {
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
private newtype TDataFlowCall =
|
private newtype TDataFlowCall =
|
||||||
|
|||||||
@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
|||||||
not instr.isResultModeled()
|
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
|
* 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
|
* 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) {
|
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||||
allocation.alwaysEscapes()
|
allocation.alwaysEscapes()
|
||||||
or
|
or
|
||||||
exists(IREscapeAnalysisConfiguration config |
|
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||||
|
or
|
||||||
|
operandConsumesEscaped(allocation)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -146,3 +146,8 @@ class DynamicAllocation extends Allocation, TDynamicAllocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate phaseNeedsSoundEscapeAnalysis() { none() }
|
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.IntegerConstant as Ints
|
||||||
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
||||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||||
private import AliasConfiguration
|
import AliasConfiguration
|
||||||
private import codeql.util.Boolean
|
private import codeql.util.Boolean
|
||||||
|
|
||||||
private class IntValue = Ints::IntValue;
|
private class IntValue = Ints::IntValue;
|
||||||
@@ -227,13 +227,15 @@ private newtype TMemoryLocation =
|
|||||||
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
|
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:
|
* one of the following:
|
||||||
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
||||||
* unknown.
|
* unknown.
|
||||||
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
|
* - `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() {
|
final string toString() {
|
||||||
if this.isMayAccess()
|
if this.isMayAccess()
|
||||||
then result = "?" + this.toStringInternal()
|
then result = "?" + this.toStringInternal()
|
||||||
@@ -294,9 +296,9 @@ abstract class MemoryLocation extends TMemoryLocation {
|
|||||||
* represented by a `MemoryLocation` that totally overlaps all other
|
* represented by a `MemoryLocation` that totally overlaps all other
|
||||||
* `MemoryLocations` in the set.
|
* `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;
|
Allocation var;
|
||||||
boolean isMayAccess;
|
boolean isMayAccess;
|
||||||
|
|
||||||
@@ -424,7 +426,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
|
|||||||
* `{a, b}` into a memory location that represents _all_ of the allocations
|
* `{a, b}` into a memory location that represents _all_ of the allocations
|
||||||
* in the set.
|
* in the set.
|
||||||
*/
|
*/
|
||||||
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation {
|
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation0 {
|
||||||
VariableGroup vg;
|
VariableGroup vg;
|
||||||
boolean isMayAccess;
|
boolean isMayAccess;
|
||||||
boolean isAll;
|
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`.
|
* 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;
|
IRFunction irFunc;
|
||||||
boolean isMayAccess;
|
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
|
* 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.
|
* not access memory on the current function's stack frame.
|
||||||
*/
|
*/
|
||||||
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
|
||||||
IRFunction irFunc;
|
IRFunction irFunc;
|
||||||
boolean isMayAccess;
|
boolean isMayAccess;
|
||||||
|
|
||||||
@@ -589,7 +591,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
|||||||
/**
|
/**
|
||||||
* An access to all aliased memory.
|
* An access to all aliased memory.
|
||||||
*/
|
*/
|
||||||
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
|
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation0 {
|
||||||
IRFunction irFunc;
|
IRFunction irFunc;
|
||||||
boolean isMayAccess;
|
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`.
|
* 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 |
|
exists(Overlap overlap |
|
||||||
// Compute the overlap based only on the extent.
|
// Compute the overlap based only on the extent.
|
||||||
overlap = getExtentOverlap(def, use) and
|
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
|
* based only on the set of memory locations accessed. Handling of "may" accesses and read-only
|
||||||
* locations occurs in `getOverlap()`.
|
* 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.
|
// 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.
|
// AllAliasedMemory must totally overlap any location within the same virtual variable.
|
||||||
@@ -861,6 +863,40 @@ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMem
|
|||||||
bindingset[result, b]
|
bindingset[result, b]
|
||||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
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) {
|
MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||||
not canReuseSsaForOldResult(instr) and
|
not canReuseSsaForOldResult(instr) and
|
||||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
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
|
not canReuseSsaForOldResult(operand.getAnyDef()) and
|
||||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
exists(MemoryAccessKind kind |
|
||||||
kind = operand.getMemoryAccess() and
|
kind = operand.getMemoryAccess() and
|
||||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) 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. */
|
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||||
int getStartBitOffset(VariableMemoryLocation location) {
|
int getStartBitOffset(VariableMemoryLocation location) {
|
||||||
result = location.getStartBitOffset() and Ints::hasValue(result)
|
result = location.getStartBitOffset() and Ints::hasValue(result)
|
||||||
|
|||||||
@@ -933,11 +933,15 @@ module DefUse {
|
|||||||
bindingset[index, block]
|
bindingset[index, block]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private int getNonChiOffset(int index, OldBlock block) {
|
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
|
if
|
||||||
getNewBlock(block) = func.getEntryBlock() and
|
block = entryBlock and
|
||||||
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
|
not i instanceof InitializeNonLocalInstruction and
|
||||||
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
|
not i instanceof AliasedDefinitionInstruction
|
||||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||||
else result = 2 * index
|
else result = 2 * index
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
|||||||
not instr.isResultModeled()
|
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
|
* 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
|
* 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) {
|
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||||
allocation.alwaysEscapes()
|
allocation.alwaysEscapes()
|
||||||
or
|
or
|
||||||
exists(IREscapeAnalysisConfiguration config |
|
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||||
|
or
|
||||||
|
operandConsumesEscaped(allocation)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
private import AliasConfigurationImports
|
private import AliasConfigurationImports
|
||||||
|
private import codeql.util.Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A memory allocation that can be tracked by the SimpleSSA alias analysis.
|
* A memory allocation that can be tracked by the SimpleSSA alias analysis.
|
||||||
@@ -16,3 +17,5 @@ class Allocation extends IRAutomaticVariable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate phaseNeedsSoundEscapeAnalysis() { any() }
|
predicate phaseNeedsSoundEscapeAnalysis() { any() }
|
||||||
|
|
||||||
|
Unit getOldAllocation(Allocation allocation) { any() }
|
||||||
|
|||||||
@@ -933,11 +933,15 @@ module DefUse {
|
|||||||
bindingset[index, block]
|
bindingset[index, block]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private int getNonChiOffset(int index, OldBlock block) {
|
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
|
if
|
||||||
getNewBlock(block) = func.getEntryBlock() and
|
block = entryBlock and
|
||||||
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
|
not i instanceof InitializeNonLocalInstruction and
|
||||||
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
|
not i instanceof AliasedDefinitionInstruction
|
||||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||||
else result = 2 * index
|
else result = 2 * index
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import AliasAnalysis
|
import AliasAnalysis
|
||||||
private import SimpleSSAImports
|
private import SimpleSSAImports
|
||||||
import SimpleSSAPublicImports
|
import SimpleSSAPublicImports
|
||||||
private import AliasConfiguration
|
import AliasConfiguration
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
|
|
||||||
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
|
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ private import implementations.StdPair
|
|||||||
private import implementations.StdMap
|
private import implementations.StdMap
|
||||||
private import implementations.StdSet
|
private import implementations.StdSet
|
||||||
private import implementations.StdString
|
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.Swap
|
||||||
private import implementations.GetDelim
|
private import implementations.GetDelim
|
||||||
private import implementations.SmartPointer
|
private import implementations.SmartPointer
|
||||||
|
|||||||
@@ -86,6 +86,41 @@ private class StdIterator extends Iterator, Class {
|
|||||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
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
|
* Gets the `FunctionInput` corresponding to an iterator parameter to
|
||||||
* user-defined operator `op`, at `index`.
|
* user-defined operator `op`, at `index`.
|
||||||
@@ -579,23 +614,43 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
|||||||
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
|
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.
|
* A `begin` member function, or a related function, that returns an iterator.
|
||||||
*/
|
*/
|
||||||
class BeginFunction extends MemberFunction {
|
class BeginFunction extends Function {
|
||||||
BeginFunction() {
|
BeginFunction() {
|
||||||
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
|
this.getUnspecifiedType() instanceof Iterator and
|
||||||
this.getType().getUnspecifiedType() instanceof Iterator
|
(
|
||||||
|
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.
|
* An `end` member function, or a related function, that returns an iterator.
|
||||||
*/
|
*/
|
||||||
class EndFunction extends MemberFunction {
|
class EndFunction extends Function {
|
||||||
EndFunction() {
|
EndFunction() {
|
||||||
this.hasName(["end", "cend", "rend", "crend"]) and
|
this.getUnspecifiedType() instanceof Iterator and
|
||||||
this.getType().getUnspecifiedType() instanceof Iterator
|
(
|
||||||
|
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
|
* A `begin` or `end` member function, or a related member function, that
|
||||||
* returns an iterator.
|
* returns an iterator.
|
||||||
*/
|
*/
|
||||||
class BeginOrEndFunction extends MemberFunction {
|
class BeginOrEndFunction extends Function {
|
||||||
BeginOrEndFunction() {
|
BeginOrEndFunction() {
|
||||||
this instanceof BeginFunction or
|
this instanceof BeginFunction or
|
||||||
this instanceof EndFunction
|
this instanceof EndFunction
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||||
import semmle.code.cpp.models.interfaces.Alias
|
import semmle.code.cpp.models.interfaces.Alias
|
||||||
|
import semmle.code.cpp.models.interfaces.SideEffect
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||||
@@ -96,7 +97,7 @@ private class Sprintf extends FormattingFunction {
|
|||||||
/**
|
/**
|
||||||
* Implements `Snprintf`.
|
* Implements `Snprintf`.
|
||||||
*/
|
*/
|
||||||
private class SnprintfImpl extends Snprintf {
|
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
|
||||||
SnprintfImpl() {
|
SnprintfImpl() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
(
|
(
|
||||||
@@ -143,6 +144,26 @@ private class SnprintfImpl extends Snprintf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override int getSizeParameterIndex() { result = 1 }
|
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.FlowSource
|
||||||
import semmle.code.cpp.models.interfaces.Iterator
|
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
|
* 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`.
|
* The standard container functions `push_back` and `push_front`.
|
||||||
*/
|
*/
|
||||||
class StdSequenceContainerPush extends MemberFunction {
|
class StdSequenceContainerPush extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||||
StdSequenceContainerPush() {
|
StdSequenceContainerPush() {
|
||||||
this.getClassAndName("push_back") instanceof Vector or
|
this.getClassAndName("push_back") instanceof Vector or
|
||||||
this.getClassAndName(["push_back", "push_front"]) instanceof Deque 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.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||||
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
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`.
|
* The standard container functions `insert` and `insert_after`.
|
||||||
*/
|
*/
|
||||||
class StdSequenceContainerInsert extends MemberFunction {
|
class StdSequenceContainerInsert extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||||
StdSequenceContainerInsert() {
|
StdSequenceContainerInsert() {
|
||||||
this.getClassAndName("insert") instanceof Deque or
|
this.getClassAndName("insert") instanceof Deque or
|
||||||
this.getClassAndName("insert") instanceof List 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.
|
* Gets the index of a parameter to this function that is an iterator.
|
||||||
*/
|
*/
|
||||||
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof 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[]`.
|
* The standard container functions `at` and `operator[]`.
|
||||||
*/
|
*/
|
||||||
class StdSequenceContainerAt extends MemberFunction {
|
class StdSequenceContainerAt extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||||
StdSequenceContainerAt() {
|
StdSequenceContainerAt() {
|
||||||
this.getClassAndName(["at", "operator[]"]) instanceof Array or
|
this.getClassAndName(["at", "operator[]"]) instanceof Array or
|
||||||
this.getClassAndName(["at", "operator[]"]) instanceof Deque or
|
this.getClassAndName(["at", "operator[]"]) instanceof Deque or
|
||||||
this.getClassAndName(["at", "operator[]"]) instanceof Vector
|
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 }
|
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.
|
* 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.Taint
|
||||||
import semmle.code.cpp.models.interfaces.DataFlow
|
import semmle.code.cpp.models.interfaces.DataFlow
|
||||||
import semmle.code.cpp.models.interfaces.Iterator
|
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.
|
* 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.
|
* 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 }
|
StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +39,23 @@ private class StdMapConstructor extends Constructor, TaintFunction {
|
|||||||
output.isQualifierObject()
|
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 }
|
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) {
|
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||||
// flow from qualifier to referenced return value
|
// flow from qualifier to referenced return value
|
||||||
input.isQualifierObject() and
|
input.isQualifierObject() and
|
||||||
@@ -144,6 +165,18 @@ private class StdMapAtModels extends StdMapAt, TaintFunction {
|
|||||||
output.isQualifierObject()
|
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() }
|
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,3 +220,63 @@ private class StdMapEqualRange extends TaintFunction {
|
|||||||
output.isReturnValue()
|
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.Taint
|
||||||
|
import semmle.code.cpp.models.interfaces.Alias
|
||||||
|
import semmle.code.cpp.models.interfaces.SideEffect
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instantiation of `std::pair<T1, T2>`.
|
* An instantiation of `std::pair<T1, T2>`.
|
||||||
@@ -37,7 +39,9 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction {
|
|||||||
/**
|
/**
|
||||||
* Additional model for `std::pair` constructors.
|
* 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 }
|
StdPairConstructor() { this.getDeclaringType() instanceof StdPair }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,4 +63,77 @@ private class StdPairConstructor extends Constructor, TaintFunction {
|
|||||||
output.isQualifierObject()
|
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.Taint
|
||||||
import semmle.code.cpp.models.interfaces.Iterator
|
import semmle.code.cpp.models.interfaces.Iterator
|
||||||
import semmle.code.cpp.models.interfaces.DataFlow
|
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.
|
* The `std::basic_string` template class instantiations.
|
||||||
@@ -78,7 +80,9 @@ abstract private class StdStringTaintFunction extends TaintFunction {
|
|||||||
* std::string b(a.begin(), a.end());
|
* 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 }
|
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||||
|
|
||||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||||
@@ -94,6 +98,42 @@ private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
|||||||
output.isQualifierObject()
|
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+`.
|
* The (non-member) `std::string` function `operator+`.
|
||||||
*/
|
*/
|
||||||
private class StdStringPlus extends StdStringTaintFunction {
|
private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||||
StdStringPlus() {
|
StdStringPlus() {
|
||||||
this.hasQualifiedName(["std", "bsl"], "operator+") and
|
this.hasQualifiedName(["std", "bsl"], "operator+") and
|
||||||
this.getUnspecifiedType() instanceof StdBasicString
|
this.getUnspecifiedType() instanceof StdBasicString
|
||||||
@@ -178,6 +218,22 @@ private class StdStringPlus extends StdStringTaintFunction {
|
|||||||
) and
|
) and
|
||||||
output.isReturnValue()
|
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
|
* All of these functions combine the existing string with a new
|
||||||
* string (or character) from one of the arguments.
|
* string (or character) from one of the arguments.
|
||||||
*/
|
*/
|
||||||
private class StdStringAppend extends StdStringTaintFunction {
|
private class StdStringAppend extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||||
StdStringAppend() {
|
StdStringAppend() {
|
||||||
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
|
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 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[]`.
|
* 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 }
|
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
|
||||||
|
|
||||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
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 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") }
|
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).
|
* 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") }
|
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),
|
* The `std::ostream` functions `operator<<` (defined as a member function),
|
||||||
* `put` and `write`.
|
* `put` and `write`.
|
||||||
|
|||||||
@@ -485,10 +485,17 @@ namespace_decls(
|
|||||||
int bodylocation: @location_default ref
|
int bodylocation: @location_default ref
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case @using.kind of
|
||||||
|
1 = @using_declaration
|
||||||
|
| 2 = @using_directive
|
||||||
|
| 3 = @using_enum_declaration
|
||||||
|
;
|
||||||
|
|
||||||
usings(
|
usings(
|
||||||
unique int id: @using,
|
unique int id: @using,
|
||||||
int element_id: @element ref,
|
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. */
|
/** The element which contains the `using` declaration. */
|
||||||
@@ -1358,6 +1365,8 @@ funbind(
|
|||||||
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Binary encoding of the allocator form.
|
||||||
|
|
||||||
case @allocator.form of
|
case @allocator.form of
|
||||||
0 = plain
|
0 = plain
|
||||||
| 1 = alignment
|
| 1 = alignment
|
||||||
@@ -1376,11 +1385,13 @@ expr_allocator(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Binary encoding of the deallocator form.
|
||||||
|
|
||||||
case @deallocator.form of
|
case @deallocator.form of
|
||||||
0 = plain
|
0 = plain
|
||||||
| 1 = size
|
| 1 = size
|
||||||
| 2 = alignment
|
| 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
|
||||||
@@ -38,11 +38,18 @@ private string getEofValue() {
|
|||||||
private predicate checkedForEof(ScanfFunctionCall call) {
|
private predicate checkedForEof(ScanfFunctionCall call) {
|
||||||
exists(IRGuardCondition gc |
|
exists(IRGuardCondition gc |
|
||||||
exists(Instruction i | i.getUnconvertedResultExpression() = call |
|
exists(Instruction i | i.getUnconvertedResultExpression() = call |
|
||||||
// call == EOF
|
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||||
gc.comparesEq(valueNumber(i).getAUse(), getEofValue().toInt(), _, _)
|
// call == EOF
|
||||||
|
val = getEofValue().toInt()
|
||||||
|
or
|
||||||
|
// call == [any positive number]
|
||||||
|
val > 0
|
||||||
|
)
|
||||||
or
|
or
|
||||||
// call < 0 (EOF is guaranteed to be negative)
|
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||||
gc.comparesLt(valueNumber(i).getAUse(), 0, true, _)
|
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||||
|
val >= 0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.models.Models
|
import semmle.code.cpp.models.Models
|
||||||
|
import semmle.code.cpp.commons.Buffer
|
||||||
|
|
||||||
predicate baseType(AllocationExpr alloc, Type base) {
|
predicate baseType(AllocationExpr alloc, Type base) {
|
||||||
exists(PointerType pointer |
|
exists(PointerType pointer |
|
||||||
@@ -30,7 +31,8 @@ predicate baseType(AllocationExpr alloc, Type base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate decideOnSize(Type t, int size) {
|
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())
|
size = min(t.getSize())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +47,8 @@ where
|
|||||||
size = 0 or
|
size = 0 or
|
||||||
(allocated / size) * size = allocated
|
(allocated / size) * size = allocated
|
||||||
) and
|
) 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,
|
select alloc,
|
||||||
"Allocated memory (" + allocated.toString() + " bytes) is not a multiple of the size of '" +
|
"Allocated memory (" + allocated.toString() + " bytes) is not a multiple of the size of '" +
|
||||||
base.getName() + "' (" + basesize.toString() + " bytes)."
|
base.getName() + "' (" + basesize.toString() + " bytes)."
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ contains sensitive data that could somehow be retrieved by an attacker.</p>
|
|||||||
</overview>
|
</overview>
|
||||||
<recommendation>
|
<recommendation>
|
||||||
|
|
||||||
<p>Use alternative platform-supplied functions that will not get optimized away. Examples of such
|
<p>Use <code>memset_s</code> (from C11) instead of <code>memset</code>, as <code>memset_s</code> will not
|
||||||
functions include <code>memset_s</code>, <code>SecureZeroMemory</code>, and <code>bzero_explicit</code>.
|
get optimized away. Alternatively use platform-supplied functions such as <code>SecureZeroMemory</code> or
|
||||||
Alternatively, passing the <code>-fno-builtin-memset</code> option to the GCC/Clang compiler usually
|
<code>bzero_explicit</code> that make the same guarantee. Passing the <code>-fno-builtin-memset</code>
|
||||||
also prevents the optimization. Finally, you can use the public-domain <code>secure_memzero</code> function
|
option to the GCC/Clang compiler usually also prevents the optimization. Finally, you can use the
|
||||||
(see references below). This function, however, is not guaranteed to work on all platforms and compilers.</p>
|
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>
|
</recommendation>
|
||||||
<example>
|
<example>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* @id cpp/unsigned-difference-expression-compared-zero
|
* @id cpp/unsigned-difference-expression-compared-zero
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
* @security-severity 9.8
|
* @security-severity 9.8
|
||||||
* @precision medium
|
* @precision high
|
||||||
* @tags security
|
* @tags security
|
||||||
* correctness
|
* correctness
|
||||||
* external/cwe/cwe-191
|
* external/cwe/cwe-191
|
||||||
|
|||||||
@@ -1,12 +1,31 @@
|
|||||||
void writeCredentials() {
|
#include <sodium.h>
|
||||||
char *password = "cleartext password";
|
#include <stdio.h>
|
||||||
FILE* file = fopen("credentials.txt", "w");
|
#include <string.h>
|
||||||
|
|
||||||
|
void writeCredentialsBad(FILE *file, const char *cleartextCredentials) {
|
||||||
// BAD: write password to disk in cleartext
|
// BAD: write password to disk in cleartext
|
||||||
fputs(password, file);
|
fputs(cleartextCredentials, file);
|
||||||
|
|
||||||
// GOOD: encrypt password first
|
|
||||||
char *encrypted = encrypt(password);
|
|
||||||
fputs(encrypted, 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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ storing them.</p>
|
|||||||
|
|
||||||
<sample src="CleartextStorage.c" />
|
<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>
|
</example>
|
||||||
<references>
|
<references>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
void bad(void) {
|
void bad(void) {
|
||||||
char *password = "cleartext password";
|
const char *password = "cleartext password";
|
||||||
sqlite3 *credentialsDB;
|
sqlite3 *credentialsDB;
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
|
|
||||||
@@ -16,14 +16,15 @@ void bad(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void good(void) {
|
void good(const char *secretKey) {
|
||||||
char *password = "cleartext password";
|
const char *password = "cleartext password";
|
||||||
sqlite3 *credentialsDB;
|
sqlite3 *credentialsDB;
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
|
|
||||||
if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) {
|
if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) {
|
||||||
// GOOD: database encryption enabled:
|
// 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);
|
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) {
|
if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) {
|
||||||
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);
|
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);
|
||||||
@@ -33,4 +34,3 @@ void good(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ In the 'GOOD' case, the database (and thus the credentials) are encrypted.</p>
|
|||||||
|
|
||||||
<sample src="CleartextSqliteDatabase.c" />
|
<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>
|
</example>
|
||||||
<references>
|
<references>
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ predicate nullCheckInThrowingNew(NewOrNewArrayExpr newExpr, GuardCondition guard
|
|||||||
from NewOrNewArrayExpr newExpr, Element element, string msg, string elementString
|
from NewOrNewArrayExpr newExpr, Element element, string msg, string elementString
|
||||||
where
|
where
|
||||||
not newExpr.isFromUninstantiatedTemplate(_) and
|
not newExpr.isFromUninstantiatedTemplate(_) and
|
||||||
|
not newExpr.isFromTemplateInstantiation(_) and
|
||||||
(
|
(
|
||||||
noThrowInTryBlock(newExpr, element) and
|
noThrowInTryBlock(newExpr, element) and
|
||||||
msg = "This allocation cannot throw. $@ is unnecessary." and
|
msg = "This allocation cannot throw. $@ is unnecessary." and
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: queryMetadata
|
||||||
|
---
|
||||||
|
* 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.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* 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.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 1.1.0
|
version: 1.1.1-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
// semmle-extractor-options: -std=c++17
|
// semmle-extractor-options: -std=c++20
|
||||||
typedef unsigned long size_t;
|
typedef unsigned long size_t;
|
||||||
namespace std {
|
namespace std {
|
||||||
enum class align_val_t : size_t {};
|
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);
|
void* operator new(size_t, float);
|
||||||
@@ -37,6 +42,11 @@ struct SizedDealloc {
|
|||||||
void operator delete[](void*, size_t);
|
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 {
|
struct alignas(128) Overaligned {
|
||||||
char a[256];
|
char a[256];
|
||||||
};
|
};
|
||||||
@@ -59,6 +69,7 @@ void OperatorDelete() {
|
|||||||
delete static_cast<int*>(nullptr); // No destructor
|
delete static_cast<int*>(nullptr); // No destructor
|
||||||
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
||||||
delete static_cast<SizedDealloc*>(nullptr); // No 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<Overaligned*>(nullptr); // No destructor, with size and alignment.
|
||||||
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
||||||
delete static_cast<const String*>(nullptr); // Pointer to const
|
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
|
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) {
|
void TestFailedInit(int n) {
|
||||||
new FailedInit();
|
new FailedInit();
|
||||||
new FailedInit[n];
|
new FailedInit[n];
|
||||||
new(1.0f) FailedInitOveraligned();
|
new(1.0f) FailedInitOveraligned();
|
||||||
new(1.0f) FailedInitOveraligned[10];
|
new(1.0f) FailedInitOveraligned[10];
|
||||||
|
new FailedInitDestroyingDelete();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- non-allocating placement new ---
|
// --- non-allocating placement new ---
|
||||||
|
|||||||
@@ -1,118 +1,123 @@
|
|||||||
newExprs
|
newExprs
|
||||||
| allocators.cpp:49:3:49:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
| allocators.cpp:59:3:59: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:60:3:60: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:61:3:61: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:62:3:62: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:63:3:63: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:64:3:64: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:65:3:65: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:126:3:126: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:128:3:128: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:130:3:130:34 | new | FailedInitDestroyingDelete | void* FailedInitDestroyingDelete::operator new(size_t) | 128 | 128 | | |
|
||||||
| allocators.cpp:135:3:135:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
|
| 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
|
newArrayExprs
|
||||||
| allocators.cpp:68:3:68:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
|
| allocators.cpp:79:3:79: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:80:3:80: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:81:3:81: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:82:3:82: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:83:3:83: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:127:3:127: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:129:3:129: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:152:3:152: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:156:3:156: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:162:13:162: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:163:13:163: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:164:13:164:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
|
||||||
newExprDeallocators
|
newExprDeallocators
|
||||||
| allocators.cpp:52:3:52:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
| allocators.cpp:62:3:62: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:63:3:63: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:126:3:126: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: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
|
newArrayExprDeallocators
|
||||||
| allocators.cpp:70:3:70:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
| allocators.cpp:81:3:81: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:83:3:83: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:127:3:127: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:129:3:129:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||||
deleteExprs
|
deleteExprs
|
||||||
| allocators.cpp:59:3:59:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized | false |
|
| allocators.cpp:69:3:69: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:70:3:70: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:71:3:71: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:72:3:72:49 | delete | DestroyingDealloc | void DestroyingDealloc::operator delete(DestroyingDealloc*, std::destroying_delete_t) | 1 | 1 | destroying | true |
|
||||||
| allocators.cpp:64:3:64:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
| 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
|
deleteArrayExprs
|
||||||
| allocators.cpp:78:3:78:37 | 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:79:3:79:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
| allocators.cpp:90:3:90: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:91:3:91: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:92:3:92: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:93:3:93: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:94:3:94:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||||
allocationFunctions
|
allocationFunctions
|
||||||
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
|
| allocators.cpp:12:7:12:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||||
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
| allocators.cpp:13:7:13:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||||
| allocators.cpp:9:7:9:18 | operator new | getSizeArg = 0, requiresDealloc |
|
| allocators.cpp:14:7:14:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||||
| allocators.cpp:10:7:10:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
| allocators.cpp:15:7:15:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||||
| allocators.cpp:121:7:121:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
|
| allocators.cpp:141:7:141:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
|
||||||
| allocators.cpp:122:7:122:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
|
| allocators.cpp:142:7:142:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
|
||||||
| allocators.cpp:123:7:123:18 | operator new | getSizeArg = 0, requiresDealloc |
|
| allocators.cpp:143:7:143:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||||
| allocators.cpp:124:7:124:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
| allocators.cpp:144:7:144:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||||
| allocators.cpp:153:7:153:12 | malloc | 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 |
|
||||||
| 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
|
allocationExprs
|
||||||
| allocators.cpp:49:3:49:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
| allocators.cpp:59:3:59:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||||
| allocators.cpp:50:3:50:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
| allocators.cpp:60:3:60:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||||
| allocators.cpp:51:3:51:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
| allocators.cpp:61:3:61:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||||
| allocators.cpp:52:3:52:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
| allocators.cpp:62:3:62:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||||
| allocators.cpp:53:3:53:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
| allocators.cpp:63:3:63:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||||
| allocators.cpp:54:3:54:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
| allocators.cpp:64:3:64:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||||
| allocators.cpp:55:3:55:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
| allocators.cpp:65:3:65:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||||
| allocators.cpp:68:3:68:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
| allocators.cpp:79:3:79: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:80:3:80: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:81:3:81: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:82:3:82:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc |
|
||||||
| allocators.cpp:72:3:72:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
|
| allocators.cpp:83:3:83:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
|
||||||
| allocators.cpp:107:3:107:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
|
| allocators.cpp:126:3:126:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
|
||||||
| allocators.cpp:108:3:108:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
|
| allocators.cpp:127:3:127:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
|
||||||
| allocators.cpp:109:3:109:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
|
| allocators.cpp:128:3:128:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
|
||||||
| allocators.cpp:110:3:110:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
|
| allocators.cpp:129:3:129:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
|
||||||
| allocators.cpp:129:3:129:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
|
| allocators.cpp:130:3:130:34 | new | getAllocatedElementType = FailedInitDestroyingDelete, getSizeBytes = 128, requiresDealloc |
|
||||||
| allocators.cpp:132:3:132:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
|
| allocators.cpp:149:3:149:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||||
| allocators.cpp:135:3:135:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
| allocators.cpp:152:3:152:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||||
| allocators.cpp:136:3:136:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
|
| allocators.cpp:155:3:155:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||||
| allocators.cpp:142:13:142:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
|
| allocators.cpp:156:3:156:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
|
||||||
| allocators.cpp:143:13:143:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
|
| allocators.cpp:162:13:162:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
|
||||||
| allocators.cpp:144:13:144:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
|
| allocators.cpp:163:13:163:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
|
||||||
| allocators.cpp:149:8:149:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
|
| allocators.cpp:164:13:164:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
|
||||||
| allocators.cpp:157:50:157:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
|
| allocators.cpp:169:8:169:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
|
||||||
| allocators.cpp:158:26:158:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
|
| allocators.cpp:177:50:177:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
|
||||||
| allocators.cpp:159:31:159:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
|
| allocators.cpp:178:26:178:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
|
||||||
| allocators.cpp:160:16:160:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
|
| allocators.cpp:179:31:179:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
|
||||||
| allocators.cpp:161:34:161:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
|
| allocators.cpp:180:16:180:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
|
||||||
| allocators.cpp:162:23:162:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
|
| allocators.cpp:181:34:181:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
|
||||||
| allocators.cpp:163:3:163:8 | call to malloc | getSizeBytes = 32, 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
|
deallocationFunctions
|
||||||
| allocators.cpp:11:6:11:20 | operator delete | getFreedArg = 0 |
|
| allocators.cpp:16:6:16:20 | operator delete | getFreedArg = 0 |
|
||||||
| allocators.cpp:12:6:12:22 | operator delete[] | getFreedArg = 0 |
|
| allocators.cpp:17:6:17:22 | operator delete[] | getFreedArg = 0 |
|
||||||
| allocators.cpp:13:6:13:20 | operator delete | getFreedArg = 0 |
|
| allocators.cpp:18:6:18:20 | operator delete | getFreedArg = 0 |
|
||||||
| allocators.cpp:14:6:14:22 | 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 |
|
| 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
|
deallocationExprs
|
||||||
| allocators.cpp:59:3:59:35 | delete | getFreedExpr = 0 |
|
| allocators.cpp:69:3:69:35 | delete | getFreedExpr = 0 |
|
||||||
| allocators.cpp:60:3:60:38 | delete | getFreedExpr = 0 |
|
| allocators.cpp:70:3:70:38 | delete | getFreedExpr = 0 |
|
||||||
| allocators.cpp:61:3:61:44 | delete | getFreedExpr = 0 |
|
| allocators.cpp:71:3:71:44 | delete | getFreedExpr = 0 |
|
||||||
| allocators.cpp:62:3:62:43 | delete | getFreedExpr = 0 |
|
| allocators.cpp:72:3:72:49 | delete | getFreedExpr = 0 |
|
||||||
| allocators.cpp:63:3:63:47 | delete | getFreedExpr = 0 |
|
| allocators.cpp:73:3:73:43 | delete | getFreedExpr = 0 |
|
||||||
| allocators.cpp:64:3:64:44 | delete | getFreedExpr = 0 |
|
| allocators.cpp:74:3:74:47 | delete | getFreedExpr = 0 |
|
||||||
| allocators.cpp:78:3:78:37 | delete[] | getFreedExpr = 0 |
|
| allocators.cpp:75:3:75:44 | delete | getFreedExpr = 0 |
|
||||||
| allocators.cpp:79:3:79:40 | delete[] | getFreedExpr = 0 |
|
| allocators.cpp:89:3:89:37 | delete[] | getFreedExpr = 0 |
|
||||||
| allocators.cpp:80:3:80:46 | delete[] | getFreedExpr = 0 |
|
| allocators.cpp:90:3:90:40 | delete[] | getFreedExpr = 0 |
|
||||||
| allocators.cpp:81:3:81:45 | delete[] | getFreedExpr = 0 |
|
| allocators.cpp:91:3:91:46 | delete[] | getFreedExpr = 0 |
|
||||||
| allocators.cpp:82:3:82:49 | delete[] | getFreedExpr = 0 |
|
| allocators.cpp:92:3:92:45 | delete[] | getFreedExpr = 0 |
|
||||||
| allocators.cpp:83:3:83:23 | delete[] | getFreedExpr = call to GetPointer |
|
| allocators.cpp:93:3:93:49 | delete[] | getFreedExpr = 0 |
|
||||||
| allocators.cpp:150:2:150:16 | call to operator delete | getFreedExpr = ptr |
|
| 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
|
type = allocatedType.toString() and
|
||||||
size = allocatedType.getSize() and
|
size = allocatedType.getSize() and
|
||||||
alignment = allocatedType.getAlignment() 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.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") 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
|
type = elementType.toString() and
|
||||||
size = elementType.getSize() and
|
size = elementType.getSize() and
|
||||||
alignment = elementType.getAlignment() 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.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") 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
|
type = deletedType.toString() and
|
||||||
size = deletedType.getSize() and
|
size = deletedType.getSize() and
|
||||||
alignment = deletedType.getAlignment() 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.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") 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
|
) and
|
||||||
if exists(expr.getDeallocatorCall())
|
if exists(expr.getDeallocatorCall())
|
||||||
then hasDeallocatorCall = true
|
then hasDeallocatorCall = true
|
||||||
@@ -108,10 +111,11 @@ query predicate deleteArrayExprs(
|
|||||||
type = elementType.toString() and
|
type = elementType.toString() and
|
||||||
size = elementType.getSize() and
|
size = elementType.getSize() and
|
||||||
alignment = elementType.getAlignment() 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.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") 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 |
|
| 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.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_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: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 |
|
| 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 | dllexport |
|
||||||
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllimport |
|
| 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.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_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: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 |
|
| 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.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_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: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: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 |
|
| 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 |
|
| 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.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_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: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: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 |
|
| 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.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 |
|
| 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.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_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: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 |
|
| var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref |
|
||||||
|
|||||||
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
|
unexpectedOperand
|
||||||
duplicateOperand
|
duplicateOperand
|
||||||
missingPhiOperand
|
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
|
missingOperandType
|
||||||
duplicateChiOperand
|
duplicateChiOperand
|
||||||
sideEffectWithoutPrimary
|
sideEffectWithoutPrimary
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ missingOperand
|
|||||||
unexpectedOperand
|
unexpectedOperand
|
||||||
duplicateOperand
|
duplicateOperand
|
||||||
missingPhiOperand
|
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
|
missingOperandType
|
||||||
duplicateChiOperand
|
duplicateChiOperand
|
||||||
sideEffectWithoutPrimary
|
sideEffectWithoutPrimary
|
||||||
|
|||||||
3095
cpp/ql/test/library-tests/ir/ir/many-defs-per-use.cpp
Normal file
3095
cpp/ql/test/library-tests/ir/ir/many-defs-per-use.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,4 +7,61 @@ class TestConstexpr {
|
|||||||
constexpr int member_const_constexpr() const { return 0; }
|
constexpr int member_const_constexpr() const { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TestExplict {
|
||||||
|
explicit TestExplict();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct TestExplicitBool {
|
||||||
|
explicit(sizeof(T) == 1)
|
||||||
|
TestExplicitBool(const T);
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit TestExplicitBool(const double) -> TestExplicitBool<int>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
explicit(sizeof(T) == 4)
|
||||||
|
TestExplicitBool(const T) -> TestExplicitBool<int>;
|
||||||
|
|
||||||
|
void TestExplicitBoolFun() {
|
||||||
|
new TestExplicitBool<char>(0);
|
||||||
|
new TestExplicitBool<int>(0);
|
||||||
|
new TestExplicitBool(0.0f);
|
||||||
|
new TestExplicitBool(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct TestExplicitBool2 {
|
||||||
|
explicit(sizeof(T) == 1)
|
||||||
|
TestExplicitBool2(const T);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
TestExplicitBool2<T>::TestExplicitBool2(const T) { }
|
||||||
|
|
||||||
|
void TestExplicitBoolFun2() {
|
||||||
|
new TestExplicitBool2<char>(0);
|
||||||
|
new TestExplicitBool2<int>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct TestExplicitBool3 {
|
||||||
|
template<typename U>
|
||||||
|
explicit(sizeof(T) == 1)
|
||||||
|
TestExplicitBool3(const T, const U);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> template<typename U>
|
||||||
|
TestExplicitBool3<T>::TestExplicitBool3(const T, const U) { }
|
||||||
|
|
||||||
|
void TestExplicitBoolFun3() {
|
||||||
|
new TestExplicitBool3<char>(0, 0);
|
||||||
|
new TestExplicitBool3<int>(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestExplicitBool4 {
|
||||||
|
explicit(sizeof(char) == 1)
|
||||||
|
TestExplicitBool4(const char);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace cpp20
|
} // namespace cpp20
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
| cpp20.cpp:15:8:15:23 | TestExplicitBool<char> | file://:0:0:0:0 | char | cpp20.cpp:17:5:17:20 | TestExplicitBool | explicit, extern, public |
|
||||||
|
| cpp20.cpp:15:8:15:23 | TestExplicitBool<int> | file://:0:0:0:0 | int | cpp20.cpp:17:5:17:20 | TestExplicitBool | extern, public |
|
||||||
|
| cpp20.cpp:34:8:34:24 | TestExplicitBool2<char> | file://:0:0:0:0 | char | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | explicit, public |
|
||||||
|
| cpp20.cpp:34:8:34:24 | TestExplicitBool2<int> | file://:0:0:0:0 | int | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | public |
|
||||||
|
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<char> | file://:0:0:0:0 | char | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | explicit, public |
|
||||||
|
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<char> | file://:0:0:0:0 | char | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | explicit, extern, public |
|
||||||
|
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<int> | file://:0:0:0:0 | int | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | public |
|
||||||
|
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<int> | file://:0:0:0:0 | int | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | extern, public |
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import cpp
|
||||||
|
|
||||||
|
from MemberFunction m, ClassTemplateInstantiation c, string specifiers
|
||||||
|
where
|
||||||
|
c.getAMember() = m and
|
||||||
|
specifiers = concat(string s | s = m.getASpecifier().getName() | s, ", ")
|
||||||
|
select c, c.getATemplateArgument(), m, specifiers
|
||||||
@@ -1,146 +1,80 @@
|
|||||||
| Class | specifiers2pp.cpp:8:7:8:13 | MyClass | MyClass | abstract |
|
| Class | specifiers2pp.cpp:8:7:8:13 | MyClass | MyClass | abstract |
|
||||||
| Class | specifiers2pp.cpp:24:7:24:14 | MyClass2 | MyClass2 | abstract |
|
| Class | specifiers2pp.cpp:24:7:24:14 | MyClass2 | MyClass2 | abstract |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr, inline, is_constexpr, private |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const, declared_constexpr, inline, is_constexpr, private |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
| Function | cpp20.cpp:10:8:10:8 | TestExplict | TestExplict | extern, inline, is_constexpr, public |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
| Function | cpp20.cpp:10:8:10:8 | TestExplict | TestExplict | extern, inline, is_constexpr, public |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
| Function | cpp20.cpp:10:8:10:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
| Function | cpp20.cpp:10:8:10:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr |
|
| Function | cpp20.cpp:11:14:11:24 | TestExplict | TestExplict | explicit, extern, public |
|
||||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | inline |
|
| Function | cpp20.cpp:17:5:17:20 | TestExplicitBool | TestExplicitBool | explicit, extern, public |
|
||||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | is_constexpr |
|
| Function | cpp20.cpp:17:5:17:20 | TestExplicitBool | TestExplicitBool | extern, public |
|
||||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | private |
|
| Function | cpp20.cpp:17:5:17:20 | TestExplicitBool | TestExplicitBool | extern, public |
|
||||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const |
|
| Function | cpp20.cpp:24:1:24:16 | TestExplicitBool | TestExplicitBool | has_trailing_return_type |
|
||||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
| Function | cpp20.cpp:40:1:40:39 | TestExplicitBool2 | TestExplicitBool2 | public |
|
||||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | inline |
|
| Function | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | TestExplicitBool2 | explicit, public |
|
||||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
| Function | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | TestExplicitBool2 | public |
|
||||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | private |
|
| Function | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | TestExplicitBool2 | public |
|
||||||
| Function | specifiers2.c:11:6:11:6 | f | f | c_linkage |
|
| Function | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | TestExplicitBool3 | explicit, public |
|
||||||
| Function | specifiers2.c:11:6:11:6 | f | f | extern |
|
| Function | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | TestExplicitBool3 | public |
|
||||||
| Function | specifiers2.c:12:13:12:13 | f | f | c_linkage |
|
| Function | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | TestExplicitBool3 | explicit, extern, public |
|
||||||
| Function | specifiers2.c:12:13:12:13 | f | f | extern |
|
| Function | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | TestExplicitBool3 | extern, public |
|
||||||
| Function | specifiers2.c:13:13:13:13 | f | f | c_linkage |
|
| Function | cpp20.cpp:55:1:55:39 | TestExplicitBool3 | TestExplicitBool3 | public |
|
||||||
| Function | specifiers2.c:13:13:13:13 | f | f | extern |
|
| Function | cpp20.cpp:62:8:62:8 | TestExplicitBool4 | TestExplicitBool4 | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2.c:15:13:15:13 | g | g | c_linkage |
|
| Function | cpp20.cpp:62:8:62:8 | TestExplicitBool4 | TestExplicitBool4 | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2.c:15:13:15:13 | g | g | extern |
|
| Function | cpp20.cpp:62:8:62:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2.c:16:13:16:13 | g | g | c_linkage |
|
| Function | cpp20.cpp:62:8:62:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2.c:16:13:16:13 | g | g | extern |
|
| Function | cpp20.cpp:64:5:64:21 | TestExplicitBool4 | TestExplicitBool4 | explicit, extern, public |
|
||||||
| Function | specifiers2.c:21:6:21:12 | somefun | somefun | c_linkage |
|
| Function | file://:0:0:0:0 | operator delete | operator delete | extern |
|
||||||
| Function | specifiers2.c:21:6:21:12 | somefun | somefun | extern |
|
| Function | file://:0:0:0:0 | operator new | operator new | extern |
|
||||||
| Function | specifiers2.c:25:12:25:14 | add | add | c_linkage |
|
| Function | specifiers2.c:11:6:11:6 | f | f | c_linkage, extern |
|
||||||
| Function | specifiers2.c:25:12:25:14 | add | add | inline |
|
| Function | specifiers2.c:12:13:12:13 | f | f | c_linkage, extern |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern |
|
| Function | specifiers2.c:13:13:13:13 | f | f | c_linkage, extern |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern |
|
| Function | specifiers2.c:15:13:15:13 | g | g | c_linkage, extern |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | inline |
|
| Function | specifiers2.c:16:13:16:13 | g | g | c_linkage, extern |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | inline |
|
| Function | specifiers2.c:21:6:21:12 | somefun | somefun | c_linkage, extern |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | is_constexpr |
|
| Function | specifiers2.c:25:12:25:14 | add | add | c_linkage, inline |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | is_constexpr |
|
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | public |
|
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | public |
|
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern, inline, public |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern |
|
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern, inline, public |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern |
|
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | explicit, extern, public |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | inline |
|
| Function | specifiers2pp.cpp:12:14:12:22 | publicFun | publicFun | inline, public |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | inline |
|
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | declared_virtual, extern, public, pure, virtual |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | public |
|
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | declared_virtual, extern, public, virtual |
|
||||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | public |
|
| Function | specifiers2pp.cpp:18:14:18:23 | privateFun | privateFun | inline, private |
|
||||||
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | explicit |
|
| Function | specifiers2pp.cpp:21:14:21:25 | protectedFun | protectedFun | inline, protected |
|
||||||
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | extern |
|
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | public |
|
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:12:14:12:22 | publicFun | publicFun | inline |
|
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern, inline, public |
|
||||||
| Function | specifiers2pp.cpp:12:14:12:22 | publicFun | publicFun | public |
|
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern, inline, public |
|
||||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | declared_virtual |
|
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern, inline, public |
|
||||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | extern |
|
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | declared_virtual, extern, override, public, virtual |
|
||||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | public |
|
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | pure |
|
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | virtual |
|
|
||||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | declared_virtual |
|
|
||||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | extern |
|
|
||||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | public |
|
|
||||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | virtual |
|
|
||||||
| Function | specifiers2pp.cpp:18:14:18:23 | privateFun | privateFun | inline |
|
|
||||||
| Function | specifiers2pp.cpp:18:14:18:23 | privateFun | privateFun | private |
|
|
||||||
| Function | specifiers2pp.cpp:21:14:21:25 | protectedFun | protectedFun | inline |
|
|
||||||
| Function | specifiers2pp.cpp:21:14:21:25 | protectedFun | protectedFun | protected |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | inline |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | inline |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | inline |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | public |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | public |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | public |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | inline |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | inline |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | public |
|
|
||||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | public |
|
|
||||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | declared_virtual |
|
|
||||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | extern |
|
|
||||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | override |
|
|
||||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | public |
|
|
||||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | virtual |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public |
|
|
||||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public |
|
|
||||||
| Function | specifiers2pp.cpp:33:5:33:18 | fun | fun | public |
|
| Function | specifiers2pp.cpp:33:5:33:18 | fun | fun | public |
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern |
|
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern |
|
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline |
|
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline |
|
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public |
|
|
||||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public |
|
|
||||||
| Function | specifiers2pp.cpp:40:12:40:18 | someFun | someFun | extern |
|
| Function | specifiers2pp.cpp:40:12:40:18 | someFun | someFun | extern |
|
||||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | c_linkage |
|
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | c_linkage, extern |
|
||||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | extern |
|
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | c_linkage, extern |
|
||||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | c_linkage |
|
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | c_linkage, static |
|
||||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | extern |
|
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | c_linkage |
|
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | static |
|
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const, declared_constexpr, inline, is_constexpr, private |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const, declared_constexpr, inline, is_constexpr, private |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
| FunctionDeclarationEntry | cpp20.cpp:11:14:11:24 | declaration of TestExplict | TestExplict | explicit |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
| FunctionDeclarationEntry | cpp20.cpp:40:23:40:23 | definition of TestExplicitBool2 | TestExplicitBool2 | explicit |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
| FunctionDeclarationEntry | cpp20.cpp:51:5:51:5 | definition of TestExplicitBool3 | TestExplicitBool3 | explicit |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
| FunctionDeclarationEntry | cpp20.cpp:51:5:51:21 | declaration of TestExplicitBool3 | TestExplicitBool3 | explicit |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
| FunctionDeclarationEntry | cpp20.cpp:64:5:64:21 | declaration of TestExplicitBool4 | TestExplicitBool4 | explicit |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage, void_param_list |
|
||||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage, extern, void_param_list |
|
||||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const |
|
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | c_linkage, extern, void_param_list |
|
||||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | declared_constexpr |
|
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | c_linkage, extern, void_param_list |
|
||||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | inline |
|
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | c_linkage, extern, void_param_list |
|
||||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | private |
|
|
||||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const |
|
|
||||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | inline |
|
|
||||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
|
||||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | private |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | void_param_list |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | extern |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | void_param_list |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | c_linkage |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | extern |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | void_param_list |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | c_linkage |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | extern |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | void_param_list |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | c_linkage |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | extern |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | void_param_list |
|
|
||||||
| FunctionDeclarationEntry | specifiers2.c:21:6:21:12 | declaration of somefun | somefun | c_linkage |
|
| FunctionDeclarationEntry | specifiers2.c:21:6:21:12 | declaration of somefun | somefun | c_linkage |
|
||||||
| FunctionDeclarationEntry | specifiers2.c:25:12:25:14 | definition of add | add | c_linkage |
|
| FunctionDeclarationEntry | specifiers2.c:25:12:25:14 | definition of add | add | c_linkage |
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:2:6:2:9 | definition of afun | afun | void_param_list |
|
| FunctionDeclarationEntry | specifiers2pp.cpp:2:6:2:9 | definition of afun | afun | void_param_list |
|
||||||
@@ -154,28 +88,19 @@
|
|||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:31:13:31:15 | declaration of fun | fun | void_param_list |
|
| FunctionDeclarationEntry | specifiers2pp.cpp:31:13:31:15 | declaration of fun | fun | void_param_list |
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:33:5:33:18 | definition of fun | fun | void_param_list |
|
| FunctionDeclarationEntry | specifiers2pp.cpp:33:5:33:18 | definition of fun | fun | void_param_list |
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:40:12:40:18 | declaration of someFun | someFun | extern |
|
| FunctionDeclarationEntry | specifiers2pp.cpp:40:12:40:18 | declaration of someFun | someFun | extern |
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:41:16:41:23 | declaration of someFun2 | someFun2 | c_linkage |
|
| FunctionDeclarationEntry | specifiers2pp.cpp:41:16:41:23 | declaration of someFun2 | someFun2 | c_linkage, extern |
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:41:16:41:23 | declaration of someFun2 | someFun2 | extern |
|
| FunctionDeclarationEntry | specifiers2pp.cpp:43:9:43:16 | declaration of someFun3 | someFun3 | c_linkage, extern |
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:43:9:43:16 | declaration of someFun3 | someFun3 | c_linkage |
|
| FunctionDeclarationEntry | specifiers2pp.cpp:44:16:44:23 | declaration of someFun4 | someFun4 | c_linkage, static |
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:43:9:43:16 | declaration of someFun3 | someFun3 | extern |
|
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:44:16:44:23 | declaration of someFun4 | someFun4 | c_linkage |
|
|
||||||
| FunctionDeclarationEntry | specifiers2pp.cpp:44:16:44:23 | declaration of someFun4 | someFun4 | static |
|
|
||||||
| TypedefType | file://:0:0:0:0 | Const | Const | const |
|
| TypedefType | file://:0:0:0:0 | Const | Const | const |
|
||||||
| TypedefType | specifiers2.c:27:19:27:26 | constInt | constInt | const |
|
| TypedefType | specifiers2.c:27:19:27:26 | constInt | constInt | const |
|
||||||
| TypedefType | specifiers2pp.cpp:47:20:47:32 | const_pointer | const_pointer | const |
|
| TypedefType | specifiers2pp.cpp:47:20:47:32 | const_pointer | const_pointer | const |
|
||||||
| TypedefType | specifiers2pp.cpp:49:32:49:53 | volatile_const_pointer | volatile_const_pointer | const |
|
| TypedefType | specifiers2pp.cpp:49:32:49:53 | volatile_const_pointer | volatile_const_pointer | const, volatile |
|
||||||
| TypedefType | specifiers2pp.cpp:49:32:49:53 | volatile_const_pointer | volatile_const_pointer | volatile |
|
| TypedefType | specifiers2pp.cpp:50:32:50:54 | volatile_const_pointer2 | volatile_const_pointer2 | const, volatile |
|
||||||
| TypedefType | specifiers2pp.cpp:50:32:50:54 | volatile_const_pointer2 | volatile_const_pointer2 | const |
|
| TypedefType | specifiers2pp.cpp:53:23:53:45 | volatile_const_pointer3 | volatile_const_pointer3 | const, volatile |
|
||||||
| TypedefType | specifiers2pp.cpp:50:32:50:54 | volatile_const_pointer2 | volatile_const_pointer2 | volatile |
|
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | const, restrict, volatile |
|
||||||
| TypedefType | specifiers2pp.cpp:53:23:53:45 | volatile_const_pointer3 | volatile_const_pointer3 | const |
|
|
||||||
| TypedefType | specifiers2pp.cpp:53:23:53:45 | volatile_const_pointer3 | volatile_const_pointer3 | volatile |
|
|
||||||
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | const |
|
|
||||||
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | restrict |
|
|
||||||
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | volatile |
|
|
||||||
| TypedefType | specifiers2pp.cpp:56:28:56:32 | Const | Const | const |
|
| TypedefType | specifiers2pp.cpp:56:28:56:32 | Const | Const | const |
|
||||||
| TypedefType | specifiers2pp.cpp:58:7:58:15 | Const_int | Const_int | const |
|
| TypedefType | specifiers2pp.cpp:58:7:58:15 | Const_int | Const_int | const |
|
||||||
| TypedefType | specifiers2pp.cpp:60:28:60:45 | volatile_Const_int | volatile_Const_int | const |
|
| TypedefType | specifiers2pp.cpp:60:28:60:45 | volatile_Const_int | volatile_Const_int | const, volatile |
|
||||||
| TypedefType | specifiers2pp.cpp:60:28:60:45 | volatile_Const_int | volatile_Const_int | volatile |
|
|
||||||
| Variable | specifiers2.c:8:12:8:12 | j | j | extern |
|
| Variable | specifiers2.c:8:12:8:12 | j | j | extern |
|
||||||
| Variable | specifiers2.c:9:12:9:12 | j | j | extern |
|
| Variable | specifiers2.c:9:12:9:12 | j | j | extern |
|
||||||
| Variable | specifiers2.c:18:21:18:23 | svi | svi | static |
|
| Variable | specifiers2.c:18:21:18:23 | svi | svi | static |
|
||||||
|
|||||||
@@ -14,16 +14,20 @@ string interesting(Element e) {
|
|||||||
e instanceof VariableDeclarationEntry and result = "VariableDeclarationEntry"
|
e instanceof VariableDeclarationEntry and result = "VariableDeclarationEntry"
|
||||||
}
|
}
|
||||||
|
|
||||||
from Element e, string name, string specifier
|
from Element e, string name, string specifiers
|
||||||
where
|
where
|
||||||
(
|
(
|
||||||
name = e.(Declaration).getName() or
|
name = e.(Declaration).getName() or
|
||||||
name = e.(DeclarationEntry).getName() or
|
name = e.(DeclarationEntry).getName() or
|
||||||
name = e.(Type).toString()
|
name = e.(Type).toString()
|
||||||
) and
|
) and
|
||||||
(
|
specifiers =
|
||||||
specifier = e.(Declaration).getASpecifier().toString() or
|
concat(string s |
|
||||||
specifier = e.(DeclarationEntry).getASpecifier() or
|
s = e.(Declaration).getASpecifier().toString() or
|
||||||
specifier = e.(TypedefType).getBaseType().getASpecifier().toString()
|
s = e.(DeclarationEntry).getASpecifier() or
|
||||||
)
|
s = e.(TypedefType).getBaseType().getASpecifier().toString()
|
||||||
select interesting(e), e, name, specifier
|
|
|
||||||
|
s, ", "
|
||||||
|
) and
|
||||||
|
specifiers != ""
|
||||||
|
select interesting(e), e, name, specifiers
|
||||||
|
|||||||
@@ -1,3 +1,22 @@
|
|||||||
|
| cpp20.cpp:17:28:17:28 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:17:28:17:28 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:17:28:17:28 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:24:24:24:24 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:40:47:40:47 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:40:47:40:47 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:40:47:40:47 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const U | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const U | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:55:47:55:47 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:55:56:55:56 | (unnamed parameter 1) | file://:0:0:0:0 | const U | file://:0:0:0:0 | const |
|
||||||
|
| cpp20.cpp:64:23:64:32 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||||
|
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const double | file://:0:0:0:0 | const |
|
||||||
| specifiers2.c:18:21:18:23 | svi | file://:0:0:0:0 | volatile int | file://:0:0:0:0 | volatile |
|
| specifiers2.c:18:21:18:23 | svi | file://:0:0:0:0 | volatile int | file://:0:0:0:0 | volatile |
|
||||||
| specifiers2.c:19:11:19:12 | ci | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
| specifiers2.c:19:11:19:12 | ci | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||||
| specifiers2.c:21:34:21:34 | p | file://:0:0:0:0 | char *__restrict__ | file://:0:0:0:0 | restrict |
|
| specifiers2.c:21:34:21:34 | p | file://:0:0:0:0 | char *__restrict__ | file://:0:0:0:0 | restrict |
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
| cpp20.cpp:17:5:17:20 | TestExplicitBool | extern, public |
|
||||||
|
| cpp20.cpp:40:1:40:39 | TestExplicitBool2 | public |
|
||||||
|
| cpp20.cpp:40:23:40:23 | TestExplicitBool2 | public |
|
||||||
|
| cpp20.cpp:55:1:55:39 | TestExplicitBool3 | public |
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import cpp
|
||||||
|
|
||||||
|
from MemberFunction m, TemplateClass c, string specifiers
|
||||||
|
where
|
||||||
|
c.getAMember() = m and
|
||||||
|
specifiers = concat(string s | s = m.getASpecifier().getName() | s, ", ")
|
||||||
|
select m, specifiers
|
||||||
@@ -26,8 +26,11 @@
|
|||||||
| test.cpp:128:15:128:16 | v4 |
|
| test.cpp:128:15:128:16 | v4 |
|
||||||
| test.cpp:185:10:185:12 | cpy |
|
| test.cpp:185:10:185:12 | cpy |
|
||||||
| test.cpp:199:10:199:12 | cpy |
|
| test.cpp:199:10:199:12 | cpy |
|
||||||
| test.cpp:208:7:208:7 | a |
|
| test.cpp:213:7:213:7 | a |
|
||||||
| test.cpp:214:7:214:7 | a |
|
| test.cpp:219:7:219:7 | a |
|
||||||
|
| test.cpp:228:14:228:18 | data1 |
|
||||||
|
| test.cpp:236:14:236:18 | data1 |
|
||||||
|
| test.cpp:237:14:237:18 | data2 |
|
||||||
| test_free.cpp:11:10:11:10 | a |
|
| test_free.cpp:11:10:11:10 | a |
|
||||||
| test_free.cpp:14:10:14:10 | a |
|
| test_free.cpp:14:10:14:10 | a |
|
||||||
| test_free.cpp:16:10:16:10 | a |
|
| test_free.cpp:16:10:16:10 | a |
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
edges
|
edges
|
||||||
| test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | provenance | |
|
| test.cpp:213:7:213:7 | pointer to free output argument | test.cpp:214:2:214:2 | a | provenance | |
|
||||||
| test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | provenance | |
|
| test.cpp:219:7:219:7 | pointer to free output argument | test.cpp:220:2:220:2 | a | provenance | |
|
||||||
|
| test.cpp:228:12:228:12 | *p [post update] [data1] | test.cpp:229:2:229:2 | *p [data1] | provenance | |
|
||||||
|
| test.cpp:228:14:228:18 | pointer to operator delete[] output argument | test.cpp:228:12:228:12 | *p [post update] [data1] | provenance | |
|
||||||
|
| test.cpp:229:2:229:2 | *p [data1] | test.cpp:229:4:229:8 | data1 | provenance | |
|
||||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | provenance | |
|
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | provenance | |
|
||||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | provenance | |
|
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | provenance | |
|
||||||
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | provenance | |
|
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | provenance | |
|
||||||
@@ -33,10 +36,14 @@ edges
|
|||||||
| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
|
| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
|
||||||
| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | provenance | |
|
| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | provenance | |
|
||||||
nodes
|
nodes
|
||||||
| test.cpp:208:7:208:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
| test.cpp:213:7:213:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||||
| test.cpp:209:2:209:2 | a | semmle.label | a |
|
| test.cpp:214:2:214:2 | a | semmle.label | a |
|
||||||
| test.cpp:214:7:214:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
| test.cpp:219:7:219:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||||
| test.cpp:215:2:215:2 | a | semmle.label | a |
|
| test.cpp:220:2:220:2 | a | semmle.label | a |
|
||||||
|
| test.cpp:228:12:228:12 | *p [post update] [data1] | semmle.label | *p [post update] [data1] |
|
||||||
|
| test.cpp:228:14:228:18 | pointer to operator delete[] output argument | semmle.label | pointer to operator delete[] output argument |
|
||||||
|
| test.cpp:229:2:229:2 | *p [data1] | semmle.label | *p [data1] |
|
||||||
|
| test.cpp:229:4:229:8 | data1 | semmle.label | data1 |
|
||||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||||
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
|
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
|
||||||
| test_free.cpp:13:5:13:6 | * ... | semmle.label | * ... |
|
| test_free.cpp:13:5:13:6 | * ... | semmle.label | * ... |
|
||||||
@@ -88,8 +95,9 @@ nodes
|
|||||||
| test_free.cpp:332:5:332:6 | * ... | semmle.label | * ... |
|
| test_free.cpp:332:5:332:6 | * ... | semmle.label | * ... |
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
#select
|
||||||
| test.cpp:209:2:209:2 | a | test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | Memory may have been previously freed by $@. | test.cpp:208:2:208:5 | call to free | call to free |
|
| test.cpp:214:2:214:2 | a | test.cpp:213:7:213:7 | pointer to free output argument | test.cpp:214:2:214:2 | a | Memory may have been previously freed by $@. | test.cpp:213:2:213:5 | call to free | call to free |
|
||||||
| test.cpp:215:2:215:2 | a | test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | Memory may have been previously freed by $@. | test.cpp:214:2:214:5 | call to free | call to free |
|
| test.cpp:220:2:220:2 | a | test.cpp:219:7:219:7 | pointer to free output argument | test.cpp:220:2:220:2 | a | Memory may have been previously freed by $@. | test.cpp:219:2:219:5 | call to free | call to free |
|
||||||
|
| test.cpp:229:4:229:8 | data1 | test.cpp:228:14:228:18 | pointer to operator delete[] output argument | test.cpp:229:4:229:8 | data1 | Memory may have been previously freed by $@. | test.cpp:228:2:228:18 | delete[] | delete[] |
|
||||||
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
| test_free.cpp:13:5:13:6 | * ... | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
| test_free.cpp:13:5:13:6 | * ... | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||||
|
|||||||
@@ -201,6 +201,11 @@ void test_strndupa_dealloc() {
|
|||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
struct DataPair {
|
||||||
|
char *data1;
|
||||||
|
char *data2;
|
||||||
|
};
|
||||||
|
|
||||||
void test_reassignment() {
|
void test_reassignment() {
|
||||||
char *a = (char *)malloc(128);
|
char *a = (char *)malloc(128);
|
||||||
char *b = (char *)malloc(128);
|
char *b = (char *)malloc(128);
|
||||||
@@ -213,4 +218,21 @@ void test_reassignment() {
|
|||||||
|
|
||||||
free(a);
|
free(a);
|
||||||
a[0] = 0; // BAD
|
a[0] = 0; // BAD
|
||||||
|
|
||||||
|
DataPair p;
|
||||||
|
p.data1 = new char[128];
|
||||||
|
p.data2 = new char[128];
|
||||||
|
p.data1[0] = 0; // GOOD
|
||||||
|
p.data2[0] = 0; // GOOD
|
||||||
|
|
||||||
|
delete [] p.data1;
|
||||||
|
p.data1[0] = 0; // BAD
|
||||||
|
p.data2[0] = 0; // GOOD
|
||||||
|
|
||||||
|
p.data1 = new char[128];
|
||||||
|
p.data1[0] = 0; // GOOD
|
||||||
|
p.data2[0] = 0; // GOOD
|
||||||
|
|
||||||
|
delete [] p.data1;
|
||||||
|
delete [] p.data2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,21 @@ edges
|
|||||||
| test.cpp:420:19:420:20 | scanf output argument | test.cpp:423:7:423:7 | i | provenance | |
|
| test.cpp:420:19:420:20 | scanf output argument | test.cpp:423:7:423:7 | i | provenance | |
|
||||||
| test.cpp:455:41:455:46 | sscanf output argument | test.cpp:460:6:460:10 | value | provenance | |
|
| test.cpp:455:41:455:46 | sscanf output argument | test.cpp:460:6:460:10 | value | provenance | |
|
||||||
| test.cpp:467:20:467:25 | scanf output argument | test.cpp:474:6:474:10 | value | provenance | |
|
| test.cpp:467:20:467:25 | scanf output argument | test.cpp:474:6:474:10 | value | provenance | |
|
||||||
|
| test.cpp:480:25:480:26 | scanf output argument | test.cpp:484:9:484:9 | i | provenance | |
|
||||||
|
| test.cpp:491:25:491:26 | scanf output argument | test.cpp:495:8:495:8 | i | provenance | |
|
||||||
|
| test.cpp:501:25:501:26 | scanf output argument | test.cpp:505:9:505:9 | i | provenance | |
|
||||||
|
| test.cpp:512:25:512:26 | scanf output argument | test.cpp:516:9:516:9 | i | provenance | |
|
||||||
|
| test.cpp:525:35:525:36 | sscanf output argument | test.cpp:527:8:527:8 | a | provenance | |
|
||||||
|
| test.cpp:525:35:525:36 | sscanf output argument | test.cpp:531:8:531:8 | a | provenance | |
|
||||||
|
| test.cpp:525:39:525:40 | sscanf output argument | test.cpp:528:8:528:8 | b | provenance | |
|
||||||
|
| test.cpp:525:39:525:40 | sscanf output argument | test.cpp:532:8:532:8 | b | provenance | |
|
||||||
|
| test.cpp:525:43:525:44 | sscanf output argument | test.cpp:533:8:533:8 | c | provenance | |
|
||||||
|
| test.cpp:541:35:541:36 | sscanf output argument | test.cpp:543:8:543:8 | d | provenance | |
|
||||||
|
| test.cpp:541:35:541:36 | sscanf output argument | test.cpp:548:8:548:8 | d | provenance | |
|
||||||
|
| test.cpp:541:39:541:40 | sscanf output argument | test.cpp:544:8:544:8 | e | provenance | |
|
||||||
|
| test.cpp:541:39:541:40 | sscanf output argument | test.cpp:549:8:549:8 | e | provenance | |
|
||||||
|
| test.cpp:541:43:541:44 | sscanf output argument | test.cpp:545:8:545:8 | f | provenance | |
|
||||||
|
| test.cpp:541:43:541:44 | sscanf output argument | test.cpp:550:8:550:8 | f | provenance | |
|
||||||
nodes
|
nodes
|
||||||
| test.cpp:34:15:34:16 | scanf output argument | semmle.label | scanf output argument |
|
| test.cpp:34:15:34:16 | scanf output argument | semmle.label | scanf output argument |
|
||||||
| test.cpp:35:7:35:7 | i | semmle.label | i |
|
| test.cpp:35:7:35:7 | i | semmle.label | i |
|
||||||
@@ -114,6 +129,31 @@ nodes
|
|||||||
| test.cpp:460:6:460:10 | value | semmle.label | value |
|
| test.cpp:460:6:460:10 | value | semmle.label | value |
|
||||||
| test.cpp:467:20:467:25 | scanf output argument | semmle.label | scanf output argument |
|
| test.cpp:467:20:467:25 | scanf output argument | semmle.label | scanf output argument |
|
||||||
| test.cpp:474:6:474:10 | value | semmle.label | value |
|
| test.cpp:474:6:474:10 | value | semmle.label | value |
|
||||||
|
| test.cpp:480:25:480:26 | scanf output argument | semmle.label | scanf output argument |
|
||||||
|
| test.cpp:484:9:484:9 | i | semmle.label | i |
|
||||||
|
| test.cpp:491:25:491:26 | scanf output argument | semmle.label | scanf output argument |
|
||||||
|
| test.cpp:495:8:495:8 | i | semmle.label | i |
|
||||||
|
| test.cpp:501:25:501:26 | scanf output argument | semmle.label | scanf output argument |
|
||||||
|
| test.cpp:505:9:505:9 | i | semmle.label | i |
|
||||||
|
| test.cpp:512:25:512:26 | scanf output argument | semmle.label | scanf output argument |
|
||||||
|
| test.cpp:516:9:516:9 | i | semmle.label | i |
|
||||||
|
| test.cpp:525:35:525:36 | sscanf output argument | semmle.label | sscanf output argument |
|
||||||
|
| test.cpp:525:39:525:40 | sscanf output argument | semmle.label | sscanf output argument |
|
||||||
|
| test.cpp:525:43:525:44 | sscanf output argument | semmle.label | sscanf output argument |
|
||||||
|
| test.cpp:527:8:527:8 | a | semmle.label | a |
|
||||||
|
| test.cpp:528:8:528:8 | b | semmle.label | b |
|
||||||
|
| test.cpp:531:8:531:8 | a | semmle.label | a |
|
||||||
|
| test.cpp:532:8:532:8 | b | semmle.label | b |
|
||||||
|
| test.cpp:533:8:533:8 | c | semmle.label | c |
|
||||||
|
| test.cpp:541:35:541:36 | sscanf output argument | semmle.label | sscanf output argument |
|
||||||
|
| test.cpp:541:39:541:40 | sscanf output argument | semmle.label | sscanf output argument |
|
||||||
|
| test.cpp:541:43:541:44 | sscanf output argument | semmle.label | sscanf output argument |
|
||||||
|
| test.cpp:543:8:543:8 | d | semmle.label | d |
|
||||||
|
| test.cpp:544:8:544:8 | e | semmle.label | e |
|
||||||
|
| test.cpp:545:8:545:8 | f | semmle.label | f |
|
||||||
|
| test.cpp:548:8:548:8 | d | semmle.label | d |
|
||||||
|
| test.cpp:549:8:549:8 | e | semmle.label | e |
|
||||||
|
| test.cpp:550:8:550:8 | f | semmle.label | f |
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
#select
|
||||||
| test.cpp:35:7:35:7 | i | test.cpp:34:15:34:16 | scanf output argument | test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
|
| test.cpp:35:7:35:7 | i | test.cpp:34:15:34:16 | scanf output argument | test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
|
||||||
@@ -134,3 +174,6 @@ subpaths
|
|||||||
| test.cpp:423:7:423:7 | i | test.cpp:420:19:420:20 | scanf output argument | test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
|
| test.cpp:423:7:423:7 | i | test.cpp:420:19:420:20 | scanf output argument | test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
|
||||||
| test.cpp:460:6:460:10 | value | test.cpp:455:41:455:46 | sscanf output argument | test.cpp:460:6:460:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:455:12:455:17 | call to sscanf | call to sscanf |
|
| test.cpp:460:6:460:10 | value | test.cpp:455:41:455:46 | sscanf output argument | test.cpp:460:6:460:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:455:12:455:17 | call to sscanf | call to sscanf |
|
||||||
| test.cpp:474:6:474:10 | value | test.cpp:467:20:467:25 | scanf output argument | test.cpp:474:6:474:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:467:8:467:12 | call to scanf | call to scanf |
|
| test.cpp:474:6:474:10 | value | test.cpp:467:20:467:25 | scanf output argument | test.cpp:474:6:474:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:467:8:467:12 | call to scanf | call to scanf |
|
||||||
|
| test.cpp:484:9:484:9 | i | test.cpp:480:25:480:26 | scanf output argument | test.cpp:484:9:484:9 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:480:13:480:17 | call to scanf | call to scanf |
|
||||||
|
| test.cpp:495:8:495:8 | i | test.cpp:491:25:491:26 | scanf output argument | test.cpp:495:8:495:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:491:13:491:17 | call to scanf | call to scanf |
|
||||||
|
| test.cpp:545:8:545:8 | f | test.cpp:541:43:541:44 | sscanf output argument | test.cpp:545:8:545:8 | f | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 3. | test.cpp:541:10:541:15 | call to sscanf | call to sscanf |
|
||||||
|
|||||||
@@ -473,3 +473,83 @@ void check_for_negative_test() {
|
|||||||
}
|
}
|
||||||
use(value);
|
use(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void multiple_checks() {
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int res = scanf("%d", &i);
|
||||||
|
|
||||||
|
if (res >= 0) {
|
||||||
|
if (res != 0) {
|
||||||
|
use(i); // GOOD: checks return value [FALSE POSITIVE]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int res = scanf("%d", &i);
|
||||||
|
|
||||||
|
if (res < 0) return;
|
||||||
|
if (res != 0) {
|
||||||
|
use(i); // GOOD: checks return value [FALSE POSITIVE]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int res = scanf("%d", &i);
|
||||||
|
|
||||||
|
if (res >= 1) {
|
||||||
|
if (res != 0) {
|
||||||
|
use(i); // GOOD: checks return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int res = scanf("%d", &i);
|
||||||
|
|
||||||
|
if (res == 1) {
|
||||||
|
if (res != 0) {
|
||||||
|
use(i); // GOOD: checks return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void switch_cases(const char *data) {
|
||||||
|
float a, b, c;
|
||||||
|
|
||||||
|
switch (sscanf(data, "%f %f %f", &a, &b, &c)) {
|
||||||
|
case 2:
|
||||||
|
use(a); // GOOD
|
||||||
|
use(b); // GOOD
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
use(a); // GOOD
|
||||||
|
use(b); // GOOD
|
||||||
|
use(c); // GOOD
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
float d, e, f;
|
||||||
|
|
||||||
|
switch (sscanf(data, "%f %f %f", &d, &e, &f)) {
|
||||||
|
case 2:
|
||||||
|
use(d); // GOOD
|
||||||
|
use(e); // GOOD
|
||||||
|
use(f); // BAD
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
use(d); // GOOD
|
||||||
|
use(e); // GOOD
|
||||||
|
use(f); // GOOD
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
| test2.c:17:20:17:25 | call to malloc | Allocated memory (33 bytes) is not a multiple of the size of 'double' (8 bytes). |
|
| test2.c:17:20:17:25 | call to malloc | Allocated memory (33 bytes) is not a multiple of the size of 'double' (8 bytes). |
|
||||||
| test2.c:32:23:32:28 | call to malloc | Allocated memory (28 bytes) is not a multiple of the size of 'long long' (8 bytes). |
|
| test2.c:32:23:32:28 | call to malloc | Allocated memory (28 bytes) is not a multiple of the size of 'long long' (8 bytes). |
|
||||||
| test2.c:33:20:33:25 | call to malloc | Allocated memory (20 bytes) is not a multiple of the size of 'double' (8 bytes). |
|
| test2.c:33:20:33:25 | call to malloc | Allocated memory (20 bytes) is not a multiple of the size of 'double' (8 bytes). |
|
||||||
|
| test2.c:85:24:85:29 | call to malloc | Allocated memory (1159 bytes) is not a multiple of the size of 'MyFixedStruct' (1032 bytes). |
|
||||||
|
|||||||
@@ -53,3 +53,34 @@ void customAllocatorTests()
|
|||||||
double *dptr1 = MyMalloc1(33); // BAD -- Not a multiple of sizeof(double) [NOT DETECTED]
|
double *dptr1 = MyMalloc1(33); // BAD -- Not a multiple of sizeof(double) [NOT DETECTED]
|
||||||
double *dptr2 = MyMalloc2(33); // BAD -- Not a multiple of sizeof(double) [NOT DETECTED]
|
double *dptr2 = MyMalloc2(33); // BAD -- Not a multiple of sizeof(double) [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- variable length data structures ---
|
||||||
|
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
|
||||||
|
typedef struct _MyVarStruct1 {
|
||||||
|
size_t dataLen;
|
||||||
|
uint8_t data[0];
|
||||||
|
} MyVarStruct1;
|
||||||
|
|
||||||
|
typedef struct _MyVarStruct2 {
|
||||||
|
size_t dataLen;
|
||||||
|
uint8_t data[1];
|
||||||
|
} MyVarStruct2;
|
||||||
|
|
||||||
|
typedef struct _MyVarStruct3 {
|
||||||
|
size_t dataLen;
|
||||||
|
uint8_t data[];
|
||||||
|
} MyVarStruct3;
|
||||||
|
|
||||||
|
typedef struct _MyFixedStruct {
|
||||||
|
size_t dataLen;
|
||||||
|
uint8_t data[1024];
|
||||||
|
} MyFixedStruct;
|
||||||
|
|
||||||
|
void varStructTests() {
|
||||||
|
MyVarStruct1 *a = malloc(sizeof(MyVarStruct1) + 127); // GOOD
|
||||||
|
MyVarStruct2 *b = malloc(sizeof(MyVarStruct2) + 127); // GOOD
|
||||||
|
MyVarStruct3 *c = malloc(sizeof(MyVarStruct3) + 127); // GOOD
|
||||||
|
MyFixedStruct *d = malloc(sizeof(MyFixedStruct) + 127); // BAD --- Not a multiple of sizeof(MyFixedStruct)
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,3 +23,4 @@
|
|||||||
| test.cpp:424:2:425:2 | for(...;...;...) ... | test.cpp:424:18:424:23 | ... < ... | 1 | i | { ... } | i | return ... |
|
| test.cpp:424:2:425:2 | for(...;...;...) ... | test.cpp:424:18:424:23 | ... < ... | 1 | i | { ... } | i | return ... |
|
||||||
| test.cpp:433:2:434:2 | for(...;...;...) ... | test.cpp:433:18:433:22 | 0 | 0 | | { ... } | 0 | return ... |
|
| test.cpp:433:2:434:2 | for(...;...;...) ... | test.cpp:433:18:433:22 | 0 | 0 | | { ... } | 0 | return ... |
|
||||||
| test.cpp:559:3:564:3 | while (...) ... | test.cpp:559:9:559:15 | call to getBool | | call to getBool | { ... } | call to getBool | ExprStmt |
|
| test.cpp:559:3:564:3 | while (...) ... | test.cpp:559:9:559:15 | call to getBool | | call to getBool | { ... } | call to getBool | ExprStmt |
|
||||||
|
| test.cpp:574:3:579:3 | while (...) ... | test.cpp:574:10:574:16 | call to getBool | | call to getBool | { ... } | call to getBool | ExprStmt |
|
||||||
|
|||||||
@@ -566,3 +566,30 @@ void test45() {
|
|||||||
*rP = NULL;
|
*rP = NULL;
|
||||||
use(r); // GOOD
|
use(r); // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test46()
|
||||||
|
{
|
||||||
|
LinkedList *r, **rP = &r;
|
||||||
|
|
||||||
|
while (getBool())
|
||||||
|
{
|
||||||
|
LinkedList *s = nullptr;
|
||||||
|
*rP = s;
|
||||||
|
rP = &s->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*rP = nullptr;
|
||||||
|
use(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
float remquo(float, float, int*);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test47() {
|
||||||
|
float x = 1.0f;
|
||||||
|
float y = 2.0f;
|
||||||
|
int quo;
|
||||||
|
std::remquo(x, y, &quo);
|
||||||
|
use(quo); // GOOD
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
| test.cpp:92:5:92:31 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
| test.cpp:92:5:92:31 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||||
| test.cpp:93:15:93:41 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
| test.cpp:93:15:93:41 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||||
| test.cpp:96:10:96:36 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
| test.cpp:96:10:96:36 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||||
| test.cpp:151:9:151:24 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:152:15:152:18 | { ... } | This catch block |
|
| test.cpp:160:9:160:24 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:161:15:161:18 | { ... } | This catch block |
|
||||||
| test.cpp:199:15:199:35 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:201:16:201:19 | { ... } | This catch block |
|
| test.cpp:229:15:229:35 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:231:16:231:19 | { ... } | This catch block |
|
||||||
| test.cpp:212:14:212:34 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:213:34:213:36 | { ... } | This catch block |
|
| test.cpp:242:14:242:34 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:243:34:243:36 | { ... } | This catch block |
|
||||||
| test.cpp:246:17:246:31 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:247:8:247:12 | ! ... | This check |
|
| test.cpp:276:17:276:31 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:277:8:277:12 | ! ... | This check |
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ void good_new_handles_nullptr() {
|
|||||||
return; // GOOD
|
return; // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
void* operator new(std::size_t count, void*) noexcept;
|
void* operator new(std::size_t count, void*) noexcept;
|
||||||
void* operator new[](std::size_t count, void*) noexcept;
|
void* operator new[](std::size_t count, void*) noexcept;
|
||||||
|
|
||||||
@@ -146,18 +148,46 @@ struct Foo {
|
|||||||
operator bool();
|
operator bool();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Bar {
|
||||||
|
Bar();
|
||||||
|
|
||||||
|
operator bool();
|
||||||
|
};
|
||||||
|
|
||||||
void bad_placement_new_with_exception_handling() {
|
void bad_placement_new_with_exception_handling() {
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
try { new (buffer) Foo; } // BAD
|
|
||||||
|
try { new (buffer) Foo; } // BAD (placement new should not fail)
|
||||||
catch (...) { }
|
catch (...) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
void good_placement_new_with_exception_handling() {
|
void good_placement_new_with_exception_handling() {
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
|
|
||||||
try { new (buffer) Foo(42); } // GOOD: Foo constructor might throw
|
try { new (buffer) Foo(42); } // GOOD: Foo constructor might throw
|
||||||
catch (...) { }
|
catch (...) { }
|
||||||
|
|
||||||
|
try { new (buffer) Bar; } // GOOD: Bar constructor might throw
|
||||||
|
catch (...) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename F> F *test_template_platement_new() {
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new (buffer) F; // GOOD: `F` constructor might throw (when `F` is `Bar`)
|
||||||
|
} catch (...) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_template_platement_new_caller() {
|
||||||
|
test_template_platement_new<Foo>();
|
||||||
|
test_template_platement_new<Bar>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
int unknown_value_without_exceptions() noexcept;
|
int unknown_value_without_exceptions() noexcept;
|
||||||
|
|
||||||
void may_throw() {
|
void may_throw() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-all
|
name: codeql/csharp-solorigate-all
|
||||||
version: 1.7.21
|
version: 1.7.22-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-queries
|
name: codeql/csharp-solorigate-queries
|
||||||
version: 1.7.21
|
version: 1.7.22-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-all
|
name: codeql/csharp-all
|
||||||
version: 1.0.4
|
version: 1.0.5-dev
|
||||||
groups: csharp
|
groups: csharp
|
||||||
dbscheme: semmlecode.csharp.dbscheme
|
dbscheme: semmlecode.csharp.dbscheme
|
||||||
extractor: csharp
|
extractor: csharp
|
||||||
|
|||||||
@@ -2444,9 +2444,6 @@ DataFlowType getNodeType(Node n) {
|
|||||||
] = result.getADelegateCreation()
|
] = result.getADelegateCreation()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a string representation of a `DataFlowType`. */
|
|
||||||
string ppReprType(DataFlowType t) { result = t.toString() }
|
|
||||||
|
|
||||||
private class DataFlowNullType extends Gvn::GvnType {
|
private class DataFlowNullType extends Gvn::GvnType {
|
||||||
DataFlowNullType() { this = Gvn::getGlobalValueNumber(any(NullType nt)) }
|
DataFlowNullType() { this = Gvn::getGlobalValueNumber(any(NullType nt)) }
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-queries
|
name: codeql/csharp-queries
|
||||||
version: 1.0.4
|
version: 1.0.5-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ The valid YAML properties in the metadata are:
|
|||||||
### Description
|
### Description
|
||||||
After the `---` line following the metadata, the rest of the markdown file is the user-visible content of the change note. This should usually be a single markdown bullet list entry (starting with `*`), although it is acceptable to have multiple bullet entries in the same change note if there are multiple changes that are closely related and have the same category metadata.
|
After the `---` line following the metadata, the rest of the markdown file is the user-visible content of the change note. This should usually be a single markdown bullet list entry (starting with `*`), although it is acceptable to have multiple bullet entries in the same change note if there are multiple changes that are closely related and have the same category metadata.
|
||||||
|
|
||||||
|
For consistency, change notes should use American English.
|
||||||
|
|
||||||
## Change categories
|
## Change categories
|
||||||
Each change note must specify a `category` property in its metadata. This category servers two purposes: It determines how the change affects the version number of the next release of the pack, and it is used to group related changes in the final changelog. There is one set of available categories for query packs, and another set of available categories for library packs.
|
Each change note must specify a `category` property in its metadata. This category servers two purposes: It determines how the change affects the version number of the next release of the pack, and it is used to group related changes in the final changelog. There is one set of available categories for query packs, and another set of available categories for library packs.
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ As a first step, let's write a query that finds all ``@Override`` annotations. A
|
|||||||
|
|
||||||
As always, it is a good idea to try this query on a CodeQL database for a Java/Kotlin project to make sure it actually produces some results. On the earlier example, it should find the annotation on ``Sub1.m``. Next, we encapsulate the concept of an ``@Override`` annotation as a CodeQL class:
|
As always, it is a good idea to try this query on a CodeQL database for a Java/Kotlin project to make sure it actually produces some results. On the earlier example, it should find the annotation on ``Sub1.m``. Next, we encapsulate the concept of an ``@Override`` annotation as a CodeQL class:
|
||||||
|
|
||||||
::
|
.. code-block:: ql
|
||||||
|
|
||||||
class OverrideAnnotation extends Annotation {
|
class OverrideAnnotation extends Annotation {
|
||||||
OverrideAnnotation() {
|
OverrideAnnotation() {
|
||||||
@@ -213,11 +213,11 @@ To do so, we first introduce a class for representing all ``@SuppressWarnings``
|
|||||||
class SuppressDeprecationWarningAnnotation extends Annotation {
|
class SuppressDeprecationWarningAnnotation extends Annotation {
|
||||||
SuppressDeprecationWarningAnnotation() {
|
SuppressDeprecationWarningAnnotation() {
|
||||||
this.getType().hasQualifiedName("java.lang", "SuppressWarnings") and
|
this.getType().hasQualifiedName("java.lang", "SuppressWarnings") and
|
||||||
this.getAValue().(Literal).getLiteral().regexpMatch(".*deprecation.*")
|
this.getAStringArrayValue("value").regexpMatch(".*deprecation.*")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Here, we use ``getAValue()`` to retrieve any annotation value: in fact, annotation type ``SuppressWarnings`` only has a single annotation element, so every ``@SuppressWarnings`` annotation only has a single annotation value. Then, we ensure that it is a literal, obtain its string value using ``getLiteral``, and check whether it contains the string ``deprecation`` using a regular expression match.
|
Here, we use ``getAStringArrayValue("value")`` to retrieve any of the suppressed warnings: ``@SuppressWarnings`` defines the warnings to suppress using the annotation element named ``value`` of type ``String[]``, and ``getAStringArrayValue`` retrieves all of the array values; the CodeQL class ``Annotation`` also has similar convenience predicates for the other possible annotation element types. Afterwards we check whether one of the values is the string ``deprecation`` using a regular expression match.
|
||||||
|
|
||||||
For real-world use, this check would have to be generalized a bit: for example, the OpenJDK Java compiler allows ``@SuppressWarnings("all")`` annotations to suppress all warnings. We may also want to make sure that ``deprecation`` is matched as an entire word, and not as part of another word, by changing the regular expression to ``".*\\bdeprecation\\b.*"``.
|
For real-world use, this check would have to be generalized a bit: for example, the OpenJDK Java compiler allows ``@SuppressWarnings("all")`` annotations to suppress all warnings. We may also want to make sure that ``deprecation`` is matched as an entire word, and not as part of another word, by changing the regular expression to ``".*\\bdeprecation\\b.*"``.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
.. _codeql-cli-2.17.6:
|
||||||
|
|
||||||
|
==========================
|
||||||
|
CodeQL 2.17.6 (2024-06-27)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
.. contents:: Contents
|
||||||
|
:depth: 2
|
||||||
|
:local:
|
||||||
|
:backlinks: none
|
||||||
|
|
||||||
|
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/code-scanning/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
|
||||||
|
|
||||||
|
Security Coverage
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
CodeQL 2.17.6 runs a total of 414 security queries when configured with the Default suite (covering 161 CWE). The Extended suite enables an additional 131 queries (covering 35 more CWE).
|
||||||
|
|
||||||
|
CodeQL CLI
|
||||||
|
----------
|
||||||
|
|
||||||
|
New Features
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* Beta support is now available for analyzing C# codebases without needing a working build. To use this, pass the :code:`--build-mode none` option to :code:`codeql database create`.
|
||||||
|
|
||||||
|
Improvements
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* The :code:`--model-packs` option is now publicly available. This option allows commands like :code:`codeql database analyze` to accept a list of model packs that are used to augment the analysis of all queries involved in the analysis.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user