Merge branch 'codeql-cli-2.18.2' into dbartol/csharp-test-hotfix

This commit is contained in:
Dave Bartolomeo
2024-08-06 13:32:08 -04:00
committed by GitHub
1369 changed files with 143622 additions and 13470 deletions

View File

@@ -14,7 +14,7 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_go", version = "0.48.0")
bazel_dep(name = "rules_go", version = "0.49.0")
bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
bazel_dep(name = "rules_python", version = "0.32.2")
@@ -23,10 +23,10 @@ bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "10.0.0")
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
bazel_dep(name = "gazelle", version = "0.37.0")
bazel_dep(name = "gazelle", version = "0.38.0")
bazel_dep(name = "rules_dotnet", version = "0.15.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "rules_rust", version = "0.46.0")
bazel_dep(name = "rules_rust", version = "0.49.1")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: description: Support explicit(bool) specifiers
compatibility: full
explicit_specifier_exprs.rel: delete

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support destroying deletes
compatibility: full

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Add relation between deduction guides and class templates
compatibility: full
deduction_guide_for_class.rel: delete

View File

@@ -1,3 +1,18 @@
## 1.4.0
### New Features
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
### Minor Analysis Improvements
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.
## 1.3.0
### New Features

View File

@@ -0,0 +1,14 @@
## 1.4.0
### New Features
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
### Minor Analysis Improvements
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.3.0
lastReleaseVersion: 1.4.0

View File

@@ -0,0 +1,14 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*1]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*2]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*3]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*4]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*5]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*6]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*7]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*8]", "ReturnValue", "taint", "manual"]

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 1.3.0
version: 1.4.0
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -158,6 +158,26 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
*/
predicate isConsteval() { this.hasSpecifier("is_consteval") }
/**
* Holds if this function is declared to be `explicit`.
*/
predicate isExplicit() { this.hasSpecifier("explicit") }
/**
* Gets the constant expression that determines whether the function is explicit.
*
* For example, for the following code the result is the expression `sizeof(T) == 1`:
* ```
* template<typename T> struct C {
* explicit(sizeof(T) == 1)
* C(const T);
* };
* ```
*/
Expr getExplicitExpr() {
explicit_specifier_exprs(underlyingElement(this), unresolveElement(result))
}
/**
* Holds if this function is declared with `__attribute__((naked))` or
* `__declspec(naked)`.
@@ -898,4 +918,11 @@ class UserDefinedLiteral extends Function {
*/
class DeductionGuide extends Function {
DeductionGuide() { functions(underlyingElement(this), _, 8) }
/**
* Gets the class template for which this is a deduction guide.
*/
TemplateClass getTemplateClass() {
deduction_guide_for_class(underlyingElement(this), unresolveElement(result))
}
}

View File

@@ -156,7 +156,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
* A C++ `using` directive or `using` declaration.
*/
class UsingEntry extends Locatable, @using {
override Location getLocation() { usings(underlyingElement(this), _, result) }
override Location getLocation() { usings(underlyingElement(this), _, result, _) }
}
/**
@@ -166,15 +166,13 @@ class UsingEntry extends Locatable, @using {
* ```
*/
class UsingDeclarationEntry extends UsingEntry {
UsingDeclarationEntry() {
not exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
}
UsingDeclarationEntry() { usings(underlyingElement(this), _, _, 1) }
/**
* Gets the declaration that is referenced by this using declaration. For
* example, `std::string` in `using std::string`.
*/
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) }
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _, _) }
override string toString() { result = "using " + this.getDeclaration().getDescription() }
}
@@ -186,19 +184,36 @@ class UsingDeclarationEntry extends UsingEntry {
* ```
*/
class UsingDirectiveEntry extends UsingEntry {
UsingDirectiveEntry() {
exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
}
UsingDirectiveEntry() { usings(underlyingElement(this), _, _, 2) }
/**
* Gets the namespace that is referenced by this using directive. For
* example, `std` in `using namespace std`.
*/
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) }
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _, _) }
override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() }
}
/**
* A C++ `using enum` declaration. For example:
* ```
* enum class Foo { a, b };
* using enum Foo;
* ```
*/
class UsingEnumDeclarationEntry extends UsingEntry {
UsingEnumDeclarationEntry() { usings(underlyingElement(this), _, _, 3) }
/**
* Gets the enumeration that is referenced by this using directive. For
* example, `Foo` in `using enum Foo`.
*/
Enum getEnum() { usings(underlyingElement(this), unresolveElement(result), _, _) }
override string toString() { result = "using enum " + this.getEnum().getQualifiedName() }
}
/**
* Holds if `g` is an instance of `GlobalNamespace`. This predicate
* is used suppress a warning in `GlobalNamespace.getADeclaration()`

View File

@@ -435,12 +435,17 @@ private predicate elementSpec(
}
/** Gets the fully templated version of `f`. */
private Function getFullyTemplatedMemberFunction(Function f) {
private Function getFullyTemplatedFunction(Function f) {
not f.isFromUninstantiatedTemplate(_) and
exists(Class c, Class templateClass, int i |
c.isConstructedFrom(templateClass) and
f = c.getAMember(i) and
result = templateClass.getCanonicalMember(i)
(
exists(Class c, Class templateClass, int i |
c.isConstructedFrom(templateClass) and
f = c.getAMember(i) and
result = templateClass.getCanonicalMember(i)
)
or
not exists(f.getDeclaringType()) and
f.isConstructedFrom(result)
)
}
@@ -464,14 +469,14 @@ string getParameterTypeWithoutTemplateArguments(Function f, int n) {
*/
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
exists(Function templateFunction |
templateFunction = getFullyTemplatedMemberFunction(f) and
templateFunction = getFullyTemplatedFunction(f) and
remaining = templateFunction.getNumberOfTemplateArguments() and
result = getParameterTypeWithoutTemplateArguments(templateFunction, n)
)
or
exists(string mid, TemplateParameter tp, Function templateFunction |
mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and
templateFunction = getFullyTemplatedMemberFunction(f) and
templateFunction = getFullyTemplatedFunction(f) and
tp = templateFunction.getTemplateArgument(remaining) and
result = mid.replaceAll(tp.getName(), "func:" + remaining.toString())
)
@@ -482,12 +487,18 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain
* with `class:N` (where `N` is the index of the template).
*/
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
// If there is a declaring type then we start by expanding the function templates
exists(Class template |
f.getDeclaringType().isConstructedFrom(template) and
remaining = template.getNumberOfTemplateArguments() and
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
)
or
// If there is no declaring type we're done after expanding the function templates
not exists(f.getDeclaringType()) and
remaining = 0 and
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
or
exists(string mid, TemplateParameter tp, Class template |
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
f.getDeclaringType().isConstructedFrom(template) and
@@ -570,38 +581,6 @@ private string getSignatureWithoutFunctionTemplateNames(
)
}
private string paramsStringPart(Function c, int i) {
not c.isFromUninstantiatedTemplate(_) and
(
i = -1 and result = "(" and exists(c)
or
exists(int n, string p | getParameterTypeName(c, n) = p |
i = 2 * n and result = p
or
i = 2 * n - 1 and result = "," and n != 0
)
or
i = 2 * c.getNumberOfParameters() and result = ")"
)
}
/**
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
*
* Returns the empty string if the callable has no parameters.
* Parameter types are represented by their type erasure.
*/
cached
private string paramsString(Function c) {
result = concat(int i | | paramsStringPart(c, i) order by i)
}
bindingset[func]
private predicate matchesSignature(Function func, string signature) {
signature = "" or
paramsString(func) = signature
}
/**
* Holds if `elementSpec(_, type, _, name, signature, _)` holds and
* - `typeArgs` represents the named template parameters supplied to `type`, and
@@ -750,17 +729,17 @@ private predicate elementSpecWithArguments0(
/**
* Holds if `elementSpec(namespace, type, subtypes, name, signature, _)` and
* `method`'s signature matches `signature`.
* `func`'s signature matches `signature`.
*
* `signature` may contain template parameter names that are bound by `type` and `name`.
*/
pragma[nomagic]
private predicate elementSpecMatchesSignature(
Function method, string namespace, string type, boolean subtypes, string name, string signature
Function func, string namespace, string type, boolean subtypes, string name, string signature
) {
elementSpec(namespace, pragma[only_bind_into](type), subtypes, pragma[only_bind_into](name),
pragma[only_bind_into](signature), _) and
signatureMatches(method, signature, type, name, 0)
signatureMatches(func, signature, type, name, 0)
}
/**
@@ -776,13 +755,22 @@ private predicate hasClassAndName(Class classWithMethod, Function method, string
)
}
bindingset[name]
pragma[inline_late]
private predicate funcHasQualifiedName(Function func, string namespace, string name) {
exists(string nameWithoutArgs |
parseAngles(name, nameWithoutArgs, _, "") and
func.hasQualifiedName(namespace, nameWithoutArgs)
)
}
/**
* Holds if `namedClass` is in namespace `namespace` and has
* name `type` (excluding any template parameters).
*/
bindingset[type, namespace]
pragma[inline_late]
private predicate hasQualifiedName(Class namedClass, string namespace, string type) {
private predicate classHasQualifiedName(Class namedClass, string namespace, string type) {
exists(string typeWithoutArgs |
parseAngles(type, typeWithoutArgs, _, "") and
namedClass.hasQualifiedName(namespace, typeWithoutArgs)
@@ -804,15 +792,16 @@ private Element interpretElement0(
string namespace, string type, boolean subtypes, string name, string signature
) {
(
elementSpec(namespace, type, subtypes, name, signature, _) and
// Non-member functions
exists(Function func |
func.hasQualifiedName(namespace, name) and
type = "" and
matchesSignature(func, signature) and
subtypes = false and
not exists(func.getDeclaringType()) and
result = func
elementSpec(namespace, type, subtypes, name, signature, _) and
subtypes = false and
type = "" and
(
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
or
signature = "" and
elementSpec(namespace, type, subtypes, name, "", _) and
funcHasQualifiedName(result, namespace, name)
)
or
// Member functions
@@ -825,7 +814,7 @@ private Element interpretElement0(
elementSpec(namespace, type, subtypes, name, "", _) and
hasClassAndName(classWithMethod, result, name)
) and
hasQualifiedName(namedClass, namespace, type) and
classHasQualifiedName(namedClass, namespace, type) and
(
// member declared in the named type or a subtype of it
subtypes = true and

View File

@@ -215,19 +215,16 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
predicate localMustFlowStep(Node node1, Node node2) { none() }
/** Gets the type of `n` used for type pruning. */
Type getNodeType(Node n) {
DataFlowType getNodeType(Node n) {
exists(n) and
result instanceof VoidType // stub implementation
}
/** Gets a string representation of a type returned by `getNodeType`. */
string ppReprType(Type t) { none() } // stub implementation
/**
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
* a node of type `t1` to a node of type `t2`.
*/
predicate compatibleTypes(Type t1, Type t2) {
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
}
@@ -243,7 +240,11 @@ class DataFlowCallable extends Function { }
class DataFlowExpr = Expr;
class DataFlowType = Type;
final private class TypeFinal = Type;
class DataFlowType extends TypeFinal {
string toString() { result = "" }
}
/** A function call relevant for data flow. */
class DataFlowCall extends Expr instanceof Call {

View File

@@ -307,6 +307,10 @@ class Expr extends StmtParent, @expr {
)
or
exists(Decltype d | d.getExpr() = this.getParentWithConversions*())
or
exists(ConstexprIfStmt constIf |
constIf.getControllingExpr() = this.getParentWithConversions*()
)
}
/**
@@ -855,6 +859,16 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
)
}
/**
* Holds if the deallocation function is a destroying delete.
*/
predicate isDestroyingDeleteDeallocation() {
exists(int form |
expr_deallocator(underlyingElement(this), _, form) and
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
)
}
/**
* Gets the type that is being allocated.
*
@@ -1025,6 +1039,16 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
)
}
/**
* Holds if the deallocation function is a destroying delete.
*/
predicate isDestroyingDeleteDeallocation() {
exists(int form |
expr_deallocator(underlyingElement(this), _, form) and
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
)
}
/**
* Gets the object or array being deleted.
*/

View File

@@ -994,9 +994,6 @@ DataFlowType getNodeType(Node n) {
result instanceof VoidType // stub implementation
}
/** Gets a string representation of a type returned by `getNodeType`. */
string ppReprType(DataFlowType t) { none() } // stub implementation
/**
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
* a node of type `t1` to a node of type `t2`.
@@ -1097,7 +1094,11 @@ class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
class DataFlowExpr = Expr;
class DataFlowType = Type;
final private class TypeFinal = Type;
class DataFlowType extends TypeFinal {
string toString() { result = "" }
}
cached
private newtype TDataFlowCall =

View File

@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
not instr.isResultModeled()
}
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
private predicate consumedAsAddressOperand(Operand operand) {
operand instanceof AddressOperand
or
exists(Operand address |
consumedAsAddressOperand(address) and
operandIsPropagated(operand, _, address.getDef())
)
}
/**
* Holds if `operand` may originate from a base instruction of an allocation,
* and that operand may transitively flow to an `AddressOperand`.
*/
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
consumedAsAddressOperand(operand) and
(
not exists(Configuration::getOldAllocation(allocation)) and
operand.getDef() = allocation.getABaseInstruction()
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromAllocationBase(address, allocation)
)
)
}
private predicate propagatedFromNonAllocationBase(Operand operand) {
exists(Instruction def |
def = operand.getDef() and
not operandIsPropagated(_, _, def) and
not def = any(Configuration::Allocation allocation).getABaseInstruction()
)
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if we cannot see all producers of an operand for which allocation also flows into.
*/
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
exists(AddressOperand address |
propagatedFromAllocationBase(address, allocation) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
* either because the allocation's address is taken within the function and escapes, or because the
@@ -346,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
predicate allocationEscapes(Configuration::Allocation allocation) {
allocation.alwaysEscapes()
or
exists(IREscapeAnalysisConfiguration config |
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
resultEscapesNonReturn(allocation.getABaseInstruction())
or
operandConsumesEscaped(allocation)
)
or
Configuration::phaseNeedsSoundEscapeAnalysis() and
resultEscapesNonReturn(allocation.getABaseInstruction())
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
}
/**

View File

@@ -146,3 +146,8 @@ class DynamicAllocation extends Allocation, TDynamicAllocation {
}
predicate phaseNeedsSoundEscapeAnalysis() { none() }
UnaliasedSsa::Allocation getOldAllocation(VariableAllocation allocation) {
UnaliasedSsa::canReuseSsaForVariable(allocation.getIRVariable()) and
result = allocation.getIRVariable()
}

View File

@@ -7,7 +7,7 @@ private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConst
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import AliasConfiguration
import AliasConfiguration
private import codeql.util.Boolean
private class IntValue = Ints::IntValue;
@@ -227,13 +227,15 @@ private newtype TMemoryLocation =
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
/**
* Represents the memory location accessed by a memory operand or memory result. In this implementation, the location is
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
* one of the following:
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
* unknown.
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
*
* Some of these memory locations will be filtered out for performance reasons before being passed to SSA construction.
*/
abstract class MemoryLocation extends TMemoryLocation {
abstract private class MemoryLocation0 extends TMemoryLocation {
final string toString() {
if this.isMayAccess()
then result = "?" + this.toStringInternal()
@@ -294,9 +296,9 @@ abstract class MemoryLocation extends TMemoryLocation {
* represented by a `MemoryLocation` that totally overlaps all other
* `MemoryLocations` in the set.
*/
abstract class VirtualVariable extends MemoryLocation { }
abstract class VirtualVariable extends MemoryLocation0 { }
abstract class AllocationMemoryLocation extends MemoryLocation {
abstract class AllocationMemoryLocation extends MemoryLocation0 {
Allocation var;
boolean isMayAccess;
@@ -424,7 +426,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
* `{a, b}` into a memory location that represents _all_ of the allocations
* in the set.
*/
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation {
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation0 {
VariableGroup vg;
boolean isMayAccess;
boolean isAll;
@@ -528,7 +530,7 @@ class GroupedVirtualVariable extends GroupedMemoryLocation, VirtualVariable {
/**
* An access to memory that is not known to be confined to a specific `IRVariable`.
*/
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation0 {
IRFunction irFunc;
boolean isMayAccess;
@@ -555,7 +557,7 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
* An access to memory that is not known to be confined to a specific `IRVariable`, but is known to
* not access memory on the current function's stack frame.
*/
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
IRFunction irFunc;
boolean isMayAccess;
@@ -589,7 +591,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
/**
* An access to all aliased memory.
*/
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation0 {
IRFunction irFunc;
boolean isMayAccess;
@@ -620,7 +622,7 @@ class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
/**
* Gets the overlap relationship between the definition location `def` and the use location `use`.
*/
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
Overlap getOverlap(MemoryLocation0 def, MemoryLocation0 use) {
exists(Overlap overlap |
// Compute the overlap based only on the extent.
overlap = getExtentOverlap(def, use) and
@@ -648,7 +650,7 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
* based only on the set of memory locations accessed. Handling of "may" accesses and read-only
* locations occurs in `getOverlap()`.
*/
private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
// The def and the use must have the same virtual variable, or no overlap is possible.
(
// AllAliasedMemory must totally overlap any location within the same virtual variable.
@@ -861,6 +863,40 @@ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMem
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
/** Gets the number of overlapping uses of `def`. */
private int numberOfOverlappingUses(MemoryLocation0 def) {
result = strictcount(MemoryLocation0 use | exists(getOverlap(def, use)))
}
/**
* Holds if `def` is a busy definition. That is, it has a large number of
* overlapping uses.
*/
private predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
/** Holds if `use` is a use that overlaps with a busy definition. */
private predicate useOverlapWithBusyDef(MemoryLocation0 use) {
exists(MemoryLocation0 def |
exists(getOverlap(def, use)) and
isBusyDef(def)
)
}
final private class FinalMemoryLocation = MemoryLocation0;
/**
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
* one of the following:
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
* unknown.
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
*
* Compared to `MemoryLocation0`, this class does not contain memory locations that represent uses of busy definitions.
*/
class MemoryLocation extends FinalMemoryLocation {
MemoryLocation() { not useOverlapWithBusyDef(this) }
}
MemoryLocation getResultMemoryLocation(Instruction instr) {
not canReuseSsaForOldResult(instr) and
exists(MemoryAccessKind kind, boolean isMayAccess |
@@ -905,9 +941,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
)
}
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
private MemoryLocation0 getOperandMemoryLocation0(MemoryOperand operand, boolean isMayAccess) {
not canReuseSsaForOldResult(operand.getAnyDef()) and
exists(MemoryAccessKind kind, boolean isMayAccess |
exists(MemoryAccessKind kind |
kind = operand.getMemoryAccess() and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
(
@@ -948,6 +984,19 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
)
}
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
exists(MemoryLocation0 use0, boolean isMayAccess |
use0 = getOperandMemoryLocation0(operand, isMayAccess)
|
result = use0
or
// If `use0` overlaps with a busy definition we turn it into a use
// of `UnknownMemoryLocation`.
not use0 instanceof MemoryLocation and
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
)
}
/** Gets the start bit offset of a `MemoryLocation`, if any. */
int getStartBitOffset(VariableMemoryLocation location) {
result = location.getStartBitOffset() and Ints::hasValue(result)

View File

@@ -933,11 +933,15 @@ module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(IRFunction func | func = block.getEnclosingIRFunction() |
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
func = block.getEnclosingIRFunction() and
i = block.getInstruction(index) and
entryBlock = func.getEntryBlock()
|
if
getNewBlock(block) = func.getEntryBlock() and
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
block = entryBlock and
not i instanceof InitializeNonLocalInstruction and
not i instanceof AliasedDefinitionInstruction
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
else result = 2 * index
)

View File

@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
not instr.isResultModeled()
}
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
private predicate consumedAsAddressOperand(Operand operand) {
operand instanceof AddressOperand
or
exists(Operand address |
consumedAsAddressOperand(address) and
operandIsPropagated(operand, _, address.getDef())
)
}
/**
* Holds if `operand` may originate from a base instruction of an allocation,
* and that operand may transitively flow to an `AddressOperand`.
*/
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
consumedAsAddressOperand(operand) and
(
not exists(Configuration::getOldAllocation(allocation)) and
operand.getDef() = allocation.getABaseInstruction()
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromAllocationBase(address, allocation)
)
)
}
private predicate propagatedFromNonAllocationBase(Operand operand) {
exists(Instruction def |
def = operand.getDef() and
not operandIsPropagated(_, _, def) and
not def = any(Configuration::Allocation allocation).getABaseInstruction()
)
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if we cannot see all producers of an operand for which allocation also flows into.
*/
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
exists(AddressOperand address |
propagatedFromAllocationBase(address, allocation) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
* either because the allocation's address is taken within the function and escapes, or because the
@@ -346,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
predicate allocationEscapes(Configuration::Allocation allocation) {
allocation.alwaysEscapes()
or
exists(IREscapeAnalysisConfiguration config |
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
resultEscapesNonReturn(allocation.getABaseInstruction())
or
operandConsumesEscaped(allocation)
)
or
Configuration::phaseNeedsSoundEscapeAnalysis() and
resultEscapesNonReturn(allocation.getABaseInstruction())
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
}
/**

View File

@@ -1,4 +1,5 @@
private import AliasConfigurationImports
private import codeql.util.Unit
/**
* A memory allocation that can be tracked by the SimpleSSA alias analysis.
@@ -16,3 +17,5 @@ class Allocation extends IRAutomaticVariable {
}
predicate phaseNeedsSoundEscapeAnalysis() { any() }
Unit getOldAllocation(Allocation allocation) { any() }

View File

@@ -933,11 +933,15 @@ module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(IRFunction func | func = block.getEnclosingIRFunction() |
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
func = block.getEnclosingIRFunction() and
i = block.getInstruction(index) and
entryBlock = func.getEntryBlock()
|
if
getNewBlock(block) = func.getEntryBlock() and
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
block = entryBlock and
not i instanceof InitializeNonLocalInstruction and
not i instanceof AliasedDefinitionInstruction
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
else result = 2 * index
)

View File

@@ -1,7 +1,7 @@
import AliasAnalysis
private import SimpleSSAImports
import SimpleSSAPublicImports
private import AliasConfiguration
import AliasConfiguration
private import codeql.util.Unit
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {

View File

@@ -27,6 +27,11 @@ private import implementations.StdPair
private import implementations.StdMap
private import implementations.StdSet
private import implementations.StdString
private import implementations.StdFunction
private import implementations.StdException
private import implementations.StdAllocator
private import implementations.StdAlgorithm
private import implementations.StdMath
private import implementations.Swap
private import implementations.GetDelim
private import implementations.SmartPointer

View File

@@ -86,6 +86,41 @@ private class StdIterator extends Iterator, Class {
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
}
private class StdReverseIterator extends Iterator, Class {
StdReverseIterator() { this.hasQualifiedName(["std", "bsl"], "reverse_iterator") }
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
}
private class StdIstreamBufIterator extends Iterator, Class {
StdIstreamBufIterator() { this.hasQualifiedName(["std", "bsl"], "istreambuf_iterator") }
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
}
private class StdIstreambufIteratorConstructor extends Constructor, SideEffectFunction,
AliasFunction
{
StdIstreambufIteratorConstructor() { this.getDeclaringType() instanceof StdIstreamBufIterator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
/**
* Gets the `FunctionInput` corresponding to an iterator parameter to
* user-defined operator `op`, at `index`.
@@ -579,23 +614,43 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
}
private string beginName() {
result = ["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]
}
/**
* A `begin` member function, or a related function, that returns an iterator.
*/
class BeginFunction extends MemberFunction {
class BeginFunction extends Function {
BeginFunction() {
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
this.getType().getUnspecifiedType() instanceof Iterator
this.getUnspecifiedType() instanceof Iterator and
(
this.hasName(beginName()) and
this instanceof MemberFunction
or
this.hasGlobalOrStdOrBslName(beginName()) and
not this instanceof MemberFunction and
this.getNumberOfParameters() = 1
)
}
}
private string endName() { result = ["end", "cend", "rend", "crend"] }
/**
* An `end` member function, or a related function, that returns an iterator.
*/
class EndFunction extends MemberFunction {
class EndFunction extends Function {
EndFunction() {
this.hasName(["end", "cend", "rend", "crend"]) and
this.getType().getUnspecifiedType() instanceof Iterator
this.getUnspecifiedType() instanceof Iterator and
(
this.hasName(endName()) and
this instanceof MemberFunction
or
this.hasGlobalOrStdOrBslName(endName()) and
this instanceof MemberFunction and
this.getNumberOfParameters() = 1
)
}
}
@@ -603,7 +658,7 @@ class EndFunction extends MemberFunction {
* A `begin` or `end` member function, or a related member function, that
* returns an iterator.
*/
class BeginOrEndFunction extends MemberFunction {
class BeginOrEndFunction extends Function {
BeginOrEndFunction() {
this instanceof BeginFunction or
this instanceof EndFunction

View File

@@ -7,6 +7,7 @@
import semmle.code.cpp.models.interfaces.FormattingFunction
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
/**
* The standard functions `printf`, `wprintf` and their glib variants.
@@ -96,7 +97,7 @@ private class Sprintf extends FormattingFunction {
/**
* Implements `Snprintf`.
*/
private class SnprintfImpl extends Snprintf {
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
SnprintfImpl() {
this instanceof TopLevelFunction and
(
@@ -143,6 +144,26 @@ private class SnprintfImpl extends Snprintf {
}
override int getSizeParameterIndex() { result = 1 }
override predicate parameterNeverEscapes(int index) {
// We don't know how many parameters are passed to the function since it's varargs, but they also don't escape.
index = this.getFormatParameterIndex()
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = this.getOutputParameterIndex(false) and buffer = true and mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
// We don't know how many parameters are passed to the function since it's varargs, but they also have read side effects.
i = this.getFormatParameterIndex() and buffer = true
}
}
/**

View File

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

View File

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

View File

@@ -4,6 +4,8 @@
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/**
* A sequence container template class (for example, `std::vector`) from the
@@ -58,7 +60,7 @@ private class Vector extends StdSequenceContainer {
/**
* The standard container functions `push_back` and `push_front`.
*/
class StdSequenceContainerPush extends MemberFunction {
class StdSequenceContainerPush extends MemberFunction, SideEffectFunction, AliasFunction {
StdSequenceContainerPush() {
this.getClassAndName("push_back") instanceof Vector or
this.getClassAndName(["push_back", "push_front"]) instanceof Deque or
@@ -74,12 +76,115 @@ class StdSequenceContainerPush extends MemberFunction {
this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
// the `std::vector<bool>` specialization doesn't take a reference as a
// parameter. So we need to check that the parameter is actually a
// reference.
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class StdSequenceContainerPopFrontOrBack extends MemberFunction, SideEffectFunction,
AliasFunction
{
StdSequenceContainerPopFrontOrBack() {
this.getClassAndName("pop_back") instanceof Vector or
this.getClassAndName("pop_front") instanceof ForwardList or
this.getClassAndName(["pop_front", "pop_back"]) instanceof Deque or
this.getClassAndName(["pop_front", "pop_back"]) instanceof List
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
private class StdSequenceContainerClear extends MemberFunction, SideEffectFunction, AliasFunction {
StdSequenceContainerClear() {
this.getClassAndName("clear") instanceof Vector or
this.getClassAndName("clear") instanceof Deque or
this.getClassAndName("clear") instanceof ForwardList or
this.getClassAndName("clear") instanceof List
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
private class StdVectorReserve extends MemberFunction, SideEffectFunction, AliasFunction {
StdVectorReserve() { this.getClassAndName("reserve") instanceof Vector }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
/**
* The standard container functions `insert` and `insert_after`.
*/
class StdSequenceContainerInsert extends MemberFunction {
class StdSequenceContainerInsert extends MemberFunction, SideEffectFunction, AliasFunction {
StdSequenceContainerInsert() {
this.getClassAndName("insert") instanceof Deque or
this.getClassAndName("insert") instanceof List or
@@ -100,17 +205,138 @@ class StdSequenceContainerInsert extends MemberFunction {
* Gets the index of a parameter to this function that is an iterator.
*/
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class StdSequenceContainerFrontBack extends MemberFunction, SideEffectFunction,
AliasFunction
{
StdSequenceContainerFrontBack() {
this.getClassAndName(["front", "back"]) instanceof Deque or
this.getClassAndName(["front", "back"]) instanceof List or
this.getClassAndName(["front", "back"]) instanceof Vector or
// forward_list does not have a 'back' member function
this.getClassAndName("front") instanceof ForwardList
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
* The standard container functions `at` and `operator[]`.
*/
class StdSequenceContainerAt extends MemberFunction {
class StdSequenceContainerAt extends MemberFunction, SideEffectFunction, AliasFunction {
StdSequenceContainerAt() {
this.getClassAndName(["at", "operator[]"]) instanceof Array or
this.getClassAndName(["at", "operator[]"]) instanceof Deque or
this.getClassAndName(["at", "operator[]"]) instanceof Vector
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdSequenceContainerMemberEquals extends MemberFunction, SideEffectFunction,
AliasFunction
{
StdSequenceContainerMemberEquals() {
this.getClassAndName("operator==") instanceof Array or
this.getClassAndName("operator==") instanceof Deque or
this.getClassAndName("operator==") instanceof Vector
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 or index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
or
i = 0 and buffer = false
}
}
private class StdSequenceContainerEquals extends Function, SideEffectFunction, AliasFunction {
StdSequenceContainerEquals() {
this.hasGlobalOrStdOrBslName("operator==") and
not this instanceof MemberFunction and
this.getNumberOfParameters() = 2 and
(
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector
or
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List
or
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque
)
}
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = [0, 1] and buffer = false
}
}
/**
@@ -142,6 +368,115 @@ class StdVectorEmplace extends StdSequenceEmplace {
StdVectorEmplace() { this.getDeclaringType() instanceof Vector }
}
private class StdSequenceSize extends MemberFunction, SideEffectFunction, AliasFunction {
StdSequenceSize() {
this.getClassAndName("size") instanceof Vector
or
this.getClassAndName("size") instanceof List
or
this.getClassAndName("size") instanceof Deque
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdSequenceDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdSequenceDestructor() {
this.getDeclaringType() instanceof Vector
or
this.getDeclaringType() instanceof List
or
this.getDeclaringType() instanceof Deque
}
private Destructor getElementDestructor() {
result.getDeclaringType() = this.getTemplateArgument(0)
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() {
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
or
not exists(this.getElementDestructor())
}
override predicate hasOnlySpecificWriteSideEffects() {
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
or
not exists(this.getElementDestructor())
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdSequenceConstructor extends Constructor, SideEffectFunction, AliasFunction {
StdSequenceConstructor() {
this.getDeclaringType() instanceof Vector
or
this.getDeclaringType() instanceof List
or
this.getDeclaringType() instanceof Deque
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class InitializerList extends Class {
InitializerList() { this.hasQualifiedName(["std", "bsl"], "initializer_list") }
Type getElementType() { result = this.getTemplateArgument(0) }
}
private class InitializerListConstructor extends Constructor, SideEffectFunction, AliasFunction {
InitializerListConstructor() { this.getDeclaringType() instanceof InitializerList }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
}
/**
* The standard vector `emplace_back` function.
*/

View File

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

View File

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

View File

@@ -5,6 +5,8 @@
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/**
* The `std::map` and `std::unordered_map` template classes.
@@ -16,7 +18,9 @@ private class MapOrUnorderedMap extends Class {
/**
* Additional model for map constructors using iterator inputs.
*/
private class StdMapConstructor extends Constructor, TaintFunction {
private class StdMapConstructor extends Constructor, TaintFunction, AliasFunction,
SideEffectFunction
{
StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
/**
@@ -35,6 +39,23 @@ private class StdMapConstructor extends Constructor, TaintFunction {
output.isQualifierObject()
)
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
/**
@@ -133,7 +154,7 @@ class StdMapAt extends MemberFunction {
StdMapAt() { this.getClassAndName(["at", "operator[]"]) instanceof MapOrUnorderedMap }
}
private class StdMapAtModels extends StdMapAt, TaintFunction {
private class StdMapAtModels extends StdMapAt, TaintFunction, AliasFunction, SideEffectFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from qualifier to referenced return value
input.isQualifierObject() and
@@ -144,6 +165,18 @@ private class StdMapAtModels extends StdMapAt, TaintFunction {
output.isQualifierObject()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
@@ -187,3 +220,63 @@ private class StdMapEqualRange extends TaintFunction {
output.isReturnValue()
}
}
class StdMapDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdMapDestructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdMapClear extends MemberFunction, SideEffectFunction, AliasFunction {
StdMapClear() { this.getClassAndName("clear") instanceof MapOrUnorderedMap }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
class StdMapSize extends MemberFunction, SideEffectFunction, AliasFunction {
StdMapSize() { this.getClassAndName("size") instanceof MapOrUnorderedMap }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}

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

View File

@@ -3,6 +3,8 @@
*/
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
/**
* An instantiation of `std::pair<T1, T2>`.
@@ -37,7 +39,9 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction {
/**
* Additional model for `std::pair` constructors.
*/
private class StdPairConstructor extends Constructor, TaintFunction {
private class StdPairConstructor extends Constructor, TaintFunction, AliasFunction,
SideEffectFunction
{
StdPairConstructor() { this.getDeclaringType() instanceof StdPair }
/**
@@ -59,4 +63,77 @@ private class StdPairConstructor extends Constructor, TaintFunction {
output.isQualifierObject()
)
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
// All the constructor parameters are references with the exception of this one:
// ```
// template<class... Args1, class... Args2>
// pair(std::piecewise_construct_t, std::tuple<Args1...> first_args, std::tuple<Args2...> second_args);
// ```
// So we need to check that the parameters are actually references
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class StdPairDestructor extends Destructor, AliasFunction, SideEffectFunction {
StdPairDestructor() { this.getDeclaringType() instanceof StdPair }
private Type getFirstType() { result = this.getDeclaringType().getTemplateArgument(0) }
private Type getSecondType() { result = this.getDeclaringType().getTemplateArgument(0) }
private Type getAType() { result = [this.getFirstType(), this.getSecondType()] }
/**
* Gets the destructor associated with the base type of this pair
*/
private Destructor getADestructor() { result.getDeclaringType() = this.getAType() }
override predicate hasOnlySpecificReadSideEffects() {
this.getADestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
or
// If there's no declared destructor for the base type then it won't have
// any strange read side effects.
not exists(this.getADestructor())
}
override predicate hasOnlySpecificWriteSideEffects() {
this.getADestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
or
// If there's no declared destructor for the base type then it won't have
// any strange write side effects.
not exists(this.getADestructor())
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate parameterNeverEscapes(int index) {
this.getADestructor().(AliasFunction).parameterNeverEscapes(index)
or
// If there's no declared destructor for the base type then it won't cause
// anything to escape.
not exists(this.getADestructor()) and
index = -1
}
}

View File

@@ -7,6 +7,8 @@
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/**
* The `std::basic_string` template class instantiations.
@@ -78,7 +80,9 @@ abstract private class StdStringTaintFunction extends TaintFunction {
* std::string b(a.begin(), a.end());
* ```
*/
private class StdStringConstructor extends Constructor, StdStringTaintFunction {
private class StdStringConstructor extends Constructor, StdStringTaintFunction, SideEffectFunction,
AliasFunction
{
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -94,6 +98,42 @@ private class StdStringConstructor extends Constructor, StdStringTaintFunction {
output.isQualifierObject()
)
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdStringDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdStringDestructor() { this.getDeclaringType() instanceof StdBasicString }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
@@ -164,7 +204,7 @@ private class StdStringFrontBack extends StdStringTaintFunction {
/**
* The (non-member) `std::string` function `operator+`.
*/
private class StdStringPlus extends StdStringTaintFunction {
private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
StdStringPlus() {
this.hasQualifiedName(["std", "bsl"], "operator+") and
this.getUnspecifiedType() instanceof StdBasicString
@@ -178,6 +218,22 @@ private class StdStringPlus extends StdStringTaintFunction {
) and
output.isReturnValue()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
or
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
buffer = true
}
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
/**
@@ -185,7 +241,7 @@ private class StdStringPlus extends StdStringTaintFunction {
* All of these functions combine the existing string with a new
* string (or character) from one of the arguments.
*/
private class StdStringAppend extends StdStringTaintFunction {
private class StdStringAppend extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
StdStringAppend() {
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
}
@@ -210,6 +266,22 @@ private class StdStringAppend extends StdStringTaintFunction {
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and mustWrite = false and buffer = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = [-1, 0] and buffer = true
}
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
/**
@@ -301,7 +373,7 @@ private class StdStringSubstr extends StdStringTaintFunction {
/**
* The `std::string` functions `at` and `operator[]`.
*/
private class StdStringAt extends StdStringTaintFunction {
private class StdStringAt extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -315,6 +387,22 @@ private class StdStringAt extends StdStringTaintFunction {
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
@@ -324,6 +412,54 @@ private class StdBasicIStream extends ClassTemplateInstantiation {
StdBasicIStream() { this.hasQualifiedName(["std", "bsl"], "basic_istream") }
}
private class StdBasicIfStream extends ClassTemplateInstantiation {
StdBasicIfStream() { this.hasQualifiedName(["std", "bsl"], "basic_ifstream") }
}
class StdBasicIfStreamConstructor extends Constructor, SideEffectFunction, AliasFunction {
StdBasicIfStreamConstructor() { this.getDeclaringType() instanceof StdBasicIfStream }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
exists(Type t | t = this.getParameter(i).getUnspecifiedType() |
t instanceof PointerType and buffer = true
or
t instanceof ReferenceType and buffer = false
)
}
}
class StdBasicIfStreamDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdBasicIfStreamDestructor() { this.getDeclaringType() instanceof StdBasicIfStream }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
* The `std::istream` function `operator>>` (defined as a member function).
*/
@@ -542,6 +678,33 @@ private class StdBasicOStream extends ClassTemplateInstantiation {
StdBasicOStream() { this.hasQualifiedName(["std", "bsl"], "basic_ostream") }
}
private class StdStringLessThan extends Function, AliasFunction, SideEffectFunction {
StdStringLessThan() {
this.hasQualifiedName(["std", "bsl"], "operator<") and
this.getNumberOfParameters() = 2 and
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
StdBasicString and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
StdBasicString
}
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = [0, 1] and buffer = false
}
}
/**
* The `std::ostream` functions `operator<<` (defined as a member function),
* `put` and `write`.

View File

@@ -409,6 +409,11 @@ function_defaulted(unique int id: @function ref);
function_prototyped(unique int id: @function ref)
deduction_guide_for_class(
int id: @function ref,
int class_template: @usertype ref
)
member_function_this_type(
unique int id: @function ref,
int this_type: @type ref
@@ -485,10 +490,17 @@ namespace_decls(
int bodylocation: @location_default ref
);
case @using.kind of
1 = @using_declaration
| 2 = @using_directive
| 3 = @using_enum_declaration
;
usings(
unique int id: @using,
int element_id: @element ref,
int location: @location_default ref
int location: @location_default ref,
int kind: int ref
);
/** The element which contains the `using` declaration. */
@@ -909,6 +921,11 @@ varspecifiers(
int spec_id: @specifier ref
);
explicit_specifier_exprs(
unique int func_id: @function ref,
int constant: @expr ref
)
attributes(
unique int id: @attribute,
int kind: int ref,
@@ -1358,6 +1375,8 @@ funbind(
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
/*
Binary encoding of the allocator form.
case @allocator.form of
0 = plain
| 1 = alignment
@@ -1376,11 +1395,13 @@ expr_allocator(
);
/*
Binary encoding of the deallocator form.
case @deallocator.form of
0 = plain
| 1 = size
| 2 = alignment
| 3 = size_and_alignment
| 4 = destroying_delete
;
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support destroying deletes
compatibility: partial

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Support using-enum declarations.
compatibility: partial
usings.rel: run usings.qlo

View File

@@ -0,0 +1,17 @@
class UsingEntry extends @using {
string toString() { none() }
}
class Element extends @element {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
from UsingEntry u, Element target, Location loc, int kind
where
usings(u, target, loc) and
if target instanceof @namespace then kind = 2 else kind = 1
select u, target, loc, kind

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add relation between deduction guides and class templates
compatibility: partial

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support explicit(bool) specifiers
compatibility: partial

View File

@@ -1,3 +1,16 @@
## 1.2.0
### Query Metadata Changes
* The precision of `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
### Minor Analysis Improvements
* Fixed false positives in the `cpp/memory-may-not-be-freed` ("Memory may not be freed") query involving class methods that returned an allocated field of that class being misidentified as allocators.
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
* The `cpp/suspicious-allocation-size` ("Not enough memory allocated for array of pointer type") query no longer produces false positives on "variable size" `struct`s.
## 1.1.0
### Query Metadata Changes

View File

@@ -39,7 +39,7 @@ predicate allocCallOrIndirect(Expr e) {
allocCallOrIndirect(rtn.getExpr())
or
// return variable assigned with alloc
exists(Variable v |
exists(StackVariable v |
v = rtn.getExpr().(VariableAccess).getTarget() and
allocCallOrIndirect(v.getAnAssignedValue()) and
not assignedToFieldOrGlobal(v, _)

View File

@@ -38,11 +38,18 @@ private string getEofValue() {
private predicate checkedForEof(ScanfFunctionCall call) {
exists(IRGuardCondition gc |
exists(Instruction i | i.getUnconvertedResultExpression() = call |
// call == EOF
gc.comparesEq(valueNumber(i).getAUse(), getEofValue().toInt(), _, _)
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
// call == EOF
val = getEofValue().toInt()
or
// call == [any positive number]
val > 0
)
or
// call < 0 (EOF is guaranteed to be negative)
gc.comparesLt(valueNumber(i).getAUse(), 0, true, _)
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
// call < [any non-negative number] (EOF is guaranteed to be negative)
val >= 0
)
)
)
}

View File

@@ -15,6 +15,7 @@
import cpp
import semmle.code.cpp.models.Models
import semmle.code.cpp.commons.Buffer
predicate baseType(AllocationExpr alloc, Type base) {
exists(PointerType pointer |
@@ -30,7 +31,8 @@ predicate baseType(AllocationExpr alloc, Type base) {
}
predicate decideOnSize(Type t, int size) {
// If the codebase has more than one type with the same name, it can have more than one size.
// If the codebase has more than one type with the same name, it can have more than one size. For
// most purposes in this query, we use the smallest.
size = min(t.getSize())
}
@@ -45,7 +47,8 @@ where
size = 0 or
(allocated / size) * size = allocated
) and
not basesize > allocated // covered by SizeCheck.ql
not basesize > allocated and // covered by SizeCheck.ql
not memberMayBeVarSize(base.getUnspecifiedType(), _) // exclude variable size types
select alloc,
"Allocated memory (" + allocated.toString() + " bytes) is not a multiple of the size of '" +
base.getName() + "' (" + basesize.toString() + " bytes)."

View File

@@ -10,11 +10,12 @@ contains sensitive data that could somehow be retrieved by an attacker.</p>
</overview>
<recommendation>
<p>Use alternative platform-supplied functions that will not get optimized away. Examples of such
functions include <code>memset_s</code>, <code>SecureZeroMemory</code>, and <code>bzero_explicit</code>.
Alternatively, passing the <code>-fno-builtin-memset</code> option to the GCC/Clang compiler usually
also prevents the optimization. Finally, you can use the public-domain <code>secure_memzero</code> function
(see references below). This function, however, is not guaranteed to work on all platforms and compilers.</p>
<p>Use <code>memset_s</code> (from C11) instead of <code>memset</code>, as <code>memset_s</code> will not
get optimized away. Alternatively use platform-supplied functions such as <code>SecureZeroMemory</code> or
<code>bzero_explicit</code> that make the same guarantee. Passing the <code>-fno-builtin-memset</code>
option to the GCC/Clang compiler usually also prevents the optimization. Finally, you can use the
public-domain <code>secure_memzero</code> function (see references below). This function, however, is not
guaranteed to work on all platforms and compilers.</p>
</recommendation>
<example>

View File

@@ -5,7 +5,7 @@
* @id cpp/unsigned-difference-expression-compared-zero
* @problem.severity warning
* @security-severity 9.8
* @precision medium
* @precision high
* @tags security
* correctness
* external/cwe/cwe-191

View File

@@ -1,12 +1,31 @@
void writeCredentials() {
char *password = "cleartext password";
FILE* file = fopen("credentials.txt", "w");
#include <sodium.h>
#include <stdio.h>
#include <string.h>
void writeCredentialsBad(FILE *file, const char *cleartextCredentials) {
// BAD: write password to disk in cleartext
fputs(password, file);
// GOOD: encrypt password first
char *encrypted = encrypt(password);
fputs(encrypted, file);
fputs(cleartextCredentials, file);
}
int writeCredentialsGood(FILE *file, const char *cleartextCredentials, const unsigned char *key, const unsigned char *nonce) {
size_t credentialsLen = strlen(cleartextCredentials);
size_t ciphertext_len = crypto_secretbox_MACBYTES + credentialsLen;
unsigned char *ciphertext = malloc(ciphertext_len);
if (!ciphertext) {
logError();
return -1;
}
// encrypt the password first
if (crypto_secretbox_easy(ciphertext, (const unsigned char *)cleartextCredentials, credentialsLen, nonce, key) != 0) {
free(ciphertext);
logError();
return -1;
}
// GOOD: write encrypted password to disk
fwrite(ciphertext, 1, ciphertext_len, file);
free(ciphertext);
return 0;
}

View File

@@ -19,15 +19,20 @@ cleartext.</p>
<example>
<p>The following example shows two ways of storing user credentials in a file. In the 'BAD' case,
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
storing them.</p>
<sample src="CleartextStorage.c" />
<p>Note that for the 'GOOD' example to work we need to link against an encryption library (in this case libsodium),
initialize it with a call to <code>sodium_init</code>, and create the key and nonce with
<code>crypto_secretbox_keygen</code> and <code>randombytes_buf</code> respectively. We also need to store those
details securely so they can be used for decryption.</p>
</example>
<references>
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>

View File

@@ -1,6 +1,6 @@
void bad(void) {
char *password = "cleartext password";
const char *password = "cleartext password";
sqlite3 *credentialsDB;
sqlite3_stmt *stmt;
@@ -16,14 +16,15 @@ void bad(void) {
}
}
void good(void) {
char *password = "cleartext password";
void good(const char *secretKey) {
const char *password = "cleartext password";
sqlite3 *credentialsDB;
sqlite3_stmt *stmt;
if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) {
// GOOD: database encryption enabled:
sqlite3_exec(credentialsDB, "PRAGMA key = 'secretKey!'", NULL, NULL, NULL);
std::string setKeyString = std::string("PRAGMA key = '") + secretKey + "'";
sqlite3_exec(credentialsDB, setKeyString.c_str(), NULL, NULL, NULL);
sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL);
if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);
@@ -33,4 +34,3 @@ void good(void) {
}
}
}

View File

@@ -20,10 +20,12 @@ In the 'GOOD' case, the database (and thus the credentials) are encrypted.</p>
<sample src="CleartextSqliteDatabase.c" />
<p>Note that for the 'GOOD' example to work we need to provide a secret key. Secure key generation and storage is required.</p>
</example>
<references>
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>

View File

@@ -232,6 +232,7 @@ predicate nullCheckInThrowingNew(NewOrNewArrayExpr newExpr, GuardCondition guard
from NewOrNewArrayExpr newExpr, Element element, string msg, string elementString
where
not newExpr.isFromUninstantiatedTemplate(_) and
not newExpr.isFromTemplateInstantiation(_) and
(
noThrowInTryBlock(newExpr, element) and
msg = "This allocation cannot throw. $@ is unnecessary." and

View File

@@ -0,0 +1,12 @@
## 1.2.0
### Query Metadata Changes
* The precision of `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
### Minor Analysis Improvements
* Fixed false positives in the `cpp/memory-may-not-be-freed` ("Memory may not be freed") query involving class methods that returned an allocated field of that class being misidentified as allocators.
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
* The `cpp/suspicious-allocation-size` ("Not enough memory allocated for array of pointer type") query no longer produces false positives on "variable size" `struct`s.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.1.0
lastReleaseVersion: 1.2.0

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.1.0
version: 1.2.0
groups:
- cpp
- queries

View File

@@ -1,7 +1,12 @@
// semmle-extractor-options: -std=c++17
// semmle-extractor-options: -std=c++20
typedef unsigned long size_t;
namespace std {
enum class align_val_t : size_t {};
struct destroying_delete_t {
explicit destroying_delete_t() = default;
};
inline constexpr destroying_delete_t destroying_delete{};
}
void* operator new(size_t, float);
@@ -37,6 +42,11 @@ struct SizedDealloc {
void operator delete[](void*, size_t);
};
struct DestroyingDealloc {
void* operator new(size_t);
void operator delete(DestroyingDealloc*, std::destroying_delete_t);
};
struct alignas(128) Overaligned {
char a[256];
};
@@ -59,6 +69,7 @@ void OperatorDelete() {
delete static_cast<int*>(nullptr); // No destructor
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
delete static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
delete static_cast<DestroyingDealloc*>(nullptr); // No destructor, with destroying delete.
delete static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
delete static_cast<const String*>(nullptr); // Pointer to const
@@ -103,11 +114,20 @@ struct alignas(128) FailedInitOveraligned {
void operator delete[](void*, std::align_val_t, float); // Aligned placement
};
struct alignas(128) FailedInitDestroyingDelete {
FailedInitDestroyingDelete();
~FailedInitDestroyingDelete();
void* operator new(size_t); // Non-placement
void operator delete(FailedInitDestroyingDelete*, std::destroying_delete_t); // Destroying delete
};
void TestFailedInit(int n) {
new FailedInit();
new FailedInit[n];
new(1.0f) FailedInitOveraligned();
new(1.0f) FailedInitOveraligned[10];
new FailedInitDestroyingDelete();
}
// --- non-allocating placement new ---

View File

@@ -1,118 +1,123 @@
newExprs
| allocators.cpp:49:3:49:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:50:3:50:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
| allocators.cpp:51:3:51:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:52:3:52:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
| allocators.cpp:53:3:53:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
| allocators.cpp:54:3:54:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
| allocators.cpp:55:3:55:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
| allocators.cpp:107:3:107:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
| allocators.cpp:129:3:129:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
| allocators.cpp:135:3:135:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
| allocators.cpp:59:3:59:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:60:3:60:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
| allocators.cpp:61:3:61:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:62:3:62:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
| allocators.cpp:63:3:63:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
| allocators.cpp:64:3:64:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
| allocators.cpp:65:3:65:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
| allocators.cpp:126:3:126:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
| allocators.cpp:128:3:128:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
| allocators.cpp:130:3:130:34 | new | FailedInitDestroyingDelete | void* FailedInitDestroyingDelete::operator new(size_t) | 128 | 128 | | |
| allocators.cpp:149:3:149:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
| allocators.cpp:155:3:155:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
newArrayExprs
| allocators.cpp:68:3:68:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
| allocators.cpp:69:3:69:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
| allocators.cpp:70:3:70:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
| allocators.cpp:79:3:79:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
| allocators.cpp:80:3:80:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
| allocators.cpp:81:3:81:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
| allocators.cpp:82:3:82:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
| allocators.cpp:83:3:83:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
| allocators.cpp:127:3:127:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
| allocators.cpp:129:3:129:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
| allocators.cpp:152:3:152:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
| allocators.cpp:156:3:156:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
| allocators.cpp:162:13:162:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
| allocators.cpp:163:13:163:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
| allocators.cpp:164:13:164:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
newExprDeallocators
| allocators.cpp:52:3:52:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:53:3:53:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
| allocators.cpp:107:3:107:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
| allocators.cpp:62:3:62:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:63:3:63:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
| allocators.cpp:126:3:126:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
| allocators.cpp:128:3:128:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
| allocators.cpp:130:3:130:34 | new | FailedInitDestroyingDelete | void FailedInitDestroyingDelete::operator delete(FailedInitDestroyingDelete*, std::destroying_delete_t) | 128 | 128 | destroying |
newArrayExprDeallocators
| allocators.cpp:70:3:70:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:72:3:72:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:108:3:108:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
| allocators.cpp:81:3:81:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:83:3:83:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:127:3:127:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
| allocators.cpp:129:3:129:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
deleteExprs
| allocators.cpp:59:3:59:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized | false |
| allocators.cpp:60:3:60:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized | true |
| allocators.cpp:62:3:62:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned | false |
| allocators.cpp:64:3:64:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
| allocators.cpp:69:3:69:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized | false |
| allocators.cpp:70:3:70:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
| allocators.cpp:71:3:71:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized | true |
| allocators.cpp:72:3:72:49 | delete | DestroyingDealloc | void DestroyingDealloc::operator delete(DestroyingDealloc*, std::destroying_delete_t) | 1 | 1 | destroying | true |
| allocators.cpp:73:3:73:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned | false |
| allocators.cpp:75:3:75:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
deleteArrayExprs
| allocators.cpp:78:3:78:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
| allocators.cpp:79:3:79:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:83:3:83:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
| allocators.cpp:89:3:89:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
| allocators.cpp:90:3:90:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:91:3:91:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
| allocators.cpp:92:3:92:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
| allocators.cpp:93:3:93:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:94:3:94:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
allocationFunctions
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |
| allocators.cpp:9:7:9:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:10:7:10:20 | operator new[] | getSizeArg = 0, requiresDealloc |
| allocators.cpp:121:7:121:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
| allocators.cpp:122:7:122:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
| allocators.cpp:123:7:123:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:124:7:124:20 | operator new[] | getSizeArg = 0, requiresDealloc |
| allocators.cpp:153:7:153:12 | malloc | getSizeArg = 0, requiresDealloc |
| allocators.cpp:12:7:12:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:13:7:13:20 | operator new[] | getSizeArg = 0, requiresDealloc |
| allocators.cpp:14:7:14:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:15:7:15:20 | operator new[] | getSizeArg = 0, requiresDealloc |
| allocators.cpp:141:7:141:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
| allocators.cpp:142:7:142:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
| allocators.cpp:143:7:143:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:144:7:144:20 | operator new[] | getSizeArg = 0, requiresDealloc |
| allocators.cpp:173:7:173:12 | malloc | getSizeArg = 0, requiresDealloc |
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
allocationExprs
| allocators.cpp:49:3:49:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:50:3:50:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:51:3:51:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:52:3:52:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
| allocators.cpp:53:3:53:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
| allocators.cpp:54:3:54:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
| allocators.cpp:55:3:55:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
| allocators.cpp:68:3:68:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
| allocators.cpp:69:3:69:18 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
| allocators.cpp:70:3:70:15 | new[] | getAllocatedElementType = String, getSizeExpr = n, getSizeMult = 8, requiresDealloc |
| allocators.cpp:71:3:71:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc |
| allocators.cpp:72:3:72:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
| allocators.cpp:107:3:107:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
| allocators.cpp:108:3:108:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
| allocators.cpp:109:3:109:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
| allocators.cpp:110:3:110:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
| allocators.cpp:129:3:129:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
| allocators.cpp:132:3:132:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
| allocators.cpp:135:3:135:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:136:3:136:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
| allocators.cpp:142:13:142:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
| allocators.cpp:143:13:143:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
| allocators.cpp:144:13:144:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
| allocators.cpp:149:8:149:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
| allocators.cpp:157:50:157:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
| allocators.cpp:158:26:158:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
| allocators.cpp:159:31:159:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
| allocators.cpp:160:16:160:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
| allocators.cpp:161:34:161:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
| allocators.cpp:162:23:162:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
| allocators.cpp:163:3:163:8 | call to malloc | getSizeBytes = 32, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
| allocators.cpp:59:3:59:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:60:3:60:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:61:3:61:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:62:3:62:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
| allocators.cpp:63:3:63:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
| allocators.cpp:64:3:64:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
| allocators.cpp:65:3:65:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
| allocators.cpp:79:3:79:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
| allocators.cpp:80:3:80:18 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
| allocators.cpp:81:3:81:15 | new[] | getAllocatedElementType = String, getSizeExpr = n, getSizeMult = 8, requiresDealloc |
| allocators.cpp:82:3:82:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc |
| allocators.cpp:83:3:83:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
| allocators.cpp:126:3:126:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
| allocators.cpp:127:3:127:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
| allocators.cpp:128:3:128:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
| allocators.cpp:129:3:129:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
| allocators.cpp:130:3:130:34 | new | getAllocatedElementType = FailedInitDestroyingDelete, getSizeBytes = 128, requiresDealloc |
| allocators.cpp:149:3:149:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
| allocators.cpp:152:3:152:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
| allocators.cpp:155:3:155:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
| allocators.cpp:156:3:156:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
| allocators.cpp:162:13:162:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
| allocators.cpp:163:13:163:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
| allocators.cpp:164:13:164:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
| allocators.cpp:169:8:169:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
| allocators.cpp:177:50:177:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
| allocators.cpp:178:26:178:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
| allocators.cpp:179:31:179:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
| allocators.cpp:180:16:180:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
| allocators.cpp:181:34:181:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
| allocators.cpp:182:23:182:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
| allocators.cpp:183:3:183:8 | call to malloc | getSizeBytes = 32, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
deallocationFunctions
| allocators.cpp:11:6:11:20 | operator delete | getFreedArg = 0 |
| allocators.cpp:12:6:12:22 | operator delete[] | getFreedArg = 0 |
| allocators.cpp:13:6:13:20 | operator delete | getFreedArg = 0 |
| allocators.cpp:14:6:14:22 | operator delete[] | getFreedArg = 0 |
| allocators.cpp:16:6:16:20 | operator delete | getFreedArg = 0 |
| allocators.cpp:17:6:17:22 | operator delete[] | getFreedArg = 0 |
| allocators.cpp:18:6:18:20 | operator delete | getFreedArg = 0 |
| allocators.cpp:19:6:19:22 | operator delete[] | getFreedArg = 0 |
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
deallocationExprs
| allocators.cpp:59:3:59:35 | delete | getFreedExpr = 0 |
| allocators.cpp:60:3:60:38 | delete | getFreedExpr = 0 |
| allocators.cpp:61:3:61:44 | delete | getFreedExpr = 0 |
| allocators.cpp:62:3:62:43 | delete | getFreedExpr = 0 |
| allocators.cpp:63:3:63:47 | delete | getFreedExpr = 0 |
| allocators.cpp:64:3:64:44 | delete | getFreedExpr = 0 |
| allocators.cpp:78:3:78:37 | delete[] | getFreedExpr = 0 |
| allocators.cpp:79:3:79:40 | delete[] | getFreedExpr = 0 |
| allocators.cpp:80:3:80:46 | delete[] | getFreedExpr = 0 |
| allocators.cpp:81:3:81:45 | delete[] | getFreedExpr = 0 |
| allocators.cpp:82:3:82:49 | delete[] | getFreedExpr = 0 |
| allocators.cpp:83:3:83:23 | delete[] | getFreedExpr = call to GetPointer |
| allocators.cpp:150:2:150:16 | call to operator delete | getFreedExpr = ptr |
| allocators.cpp:69:3:69:35 | delete | getFreedExpr = 0 |
| allocators.cpp:70:3:70:38 | delete | getFreedExpr = 0 |
| allocators.cpp:71:3:71:44 | delete | getFreedExpr = 0 |
| allocators.cpp:72:3:72:49 | delete | getFreedExpr = 0 |
| allocators.cpp:73:3:73:43 | delete | getFreedExpr = 0 |
| allocators.cpp:74:3:74:47 | delete | getFreedExpr = 0 |
| allocators.cpp:75:3:75:44 | delete | getFreedExpr = 0 |
| allocators.cpp:89:3:89:37 | delete[] | getFreedExpr = 0 |
| allocators.cpp:90:3:90:40 | delete[] | getFreedExpr = 0 |
| allocators.cpp:91:3:91:46 | delete[] | getFreedExpr = 0 |
| allocators.cpp:92:3:92:45 | delete[] | getFreedExpr = 0 |
| allocators.cpp:93:3:93:49 | delete[] | getFreedExpr = 0 |
| allocators.cpp:94:3:94:23 | delete[] | getFreedExpr = call to GetPointer |
| allocators.cpp:170:2:170:16 | call to operator delete | getFreedExpr = ptr |

View File

@@ -50,10 +50,11 @@ query predicate newExprDeallocators(
type = allocatedType.toString() and
size = allocatedType.getSize() and
alignment = allocatedType.getAlignment() and
exists(string sized, string aligned |
exists(string sized, string aligned, string destroying |
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
form = sized + " " + aligned
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
form = sized + " " + aligned + " " + destroying
)
)
}
@@ -68,10 +69,11 @@ query predicate newArrayExprDeallocators(
type = elementType.toString() and
size = elementType.getSize() and
alignment = elementType.getAlignment() and
exists(string sized, string aligned |
exists(string sized, string aligned, string destroying |
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
form = sized + " " + aligned
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
form = sized + " " + aligned + " " + destroying
)
)
}
@@ -87,10 +89,11 @@ query predicate deleteExprs(
type = deletedType.toString() and
size = deletedType.getSize() and
alignment = deletedType.getAlignment() and
exists(string sized, string aligned |
exists(string sized, string aligned, string destroying |
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
form = sized + " " + aligned
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
form = sized + " " + aligned + " " + destroying
) and
if exists(expr.getDeallocatorCall())
then hasDeallocatorCall = true
@@ -108,10 +111,11 @@ query predicate deleteArrayExprs(
type = elementType.toString() and
size = elementType.getSize() and
alignment = elementType.getAlignment() and
exists(string sized, string aligned |
exists(string sized, string aligned, string destroying |
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
form = sized + " " + aligned
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
form = sized + " " + aligned + " " + destroying
)
)
}

View File

@@ -1,7 +1,5 @@
| declspec.cpp:4:23:4:43 | Use fatal() instead | declspec.cpp:4:59:4:62 | exit | declspec.cpp:4:12:4:21 | deprecated | Use fatal() instead |
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
| routine_attributes.c:3:53:3:59 | dummy | routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref | dummy |
| routine_attributes.c:4:62:4:68 | dummy | routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:55:4:59 | alias | dummy |

View File

@@ -19,8 +19,6 @@
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllexport |
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllimport |
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
| routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref |
| routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:46:4:52 | weakref |

View File

@@ -1,6 +1,5 @@
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility | type_attributes2.cpp:5:7:5:12 | hidden |
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
| type_attributes_ms.cpp:4:67:4:75 | IDispatch | type_attributes_ms.cpp:4:19:4:22 | uuid | type_attributes_ms.cpp:4:24:4:63 | {00020400-0000-0000-c000-000000000046} |
| type_attributes_ms.cpp:5:30:5:33 | Str1 | type_attributes_ms.cpp:5:12:5:16 | align | type_attributes_ms.cpp:5:18:5:19 | 32 |
| type_attributes_ms.cpp:6:55:6:62 | IUnknown | type_attributes_ms.cpp:6:2:6:2 | uuid | type_attributes_ms.cpp:6:2:6:2 | 00000000-0000-0000-c000-000000000046 |

View File

@@ -1,7 +1,6 @@
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility |
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
| type_attributes.c:10:54:10:54 | (unnamed class/struct/union) | type_attributes.c:10:30:10:50 | transparent_union |
| type_attributes.c:16:54:16:54 | (unnamed class/struct/union) | type_attributes.c:16:30:16:50 | transparent_union |

View File

@@ -7,8 +7,6 @@
| ms_var_attributes.cpp:20:34:20:37 | pBuf | ms_var_attributes.cpp:20:12:20:12 | SAL_volatile |
| ms_var_attributes.h:5:22:5:27 | myInt3 | ms_var_attributes.h:5:1:5:9 | dllexport |
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
| var_attributes.c:1:12:1:19 | weak_var | var_attributes.c:1:36:1:39 | weak |
| var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref |

View File

@@ -11,14 +11,14 @@ edges
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:2 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | Src:MaD:0 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:1 |
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:644 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | Src:MaD:642 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:13:18:13:18 | x | provenance | |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:13:10:13:16 | call to ymlStep | provenance | |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:1 |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
| test.cpp:13:18:13:18 | x | test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | provenance | |
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:2 |
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:644 |
nodes
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | semmle.label | [summary param] *0 in buffer |
| asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | semmle.label | [summary] to write: ReturnValue in buffer |

View File

@@ -16,6 +16,7 @@
| Dubious signature "(const_iterator,size_type,const T &)" in summary model. |
| Dubious signature "(deque &&)" in summary model. |
| Dubious signature "(deque &&,const Allocator &)" in summary model. |
| Dubious signature "(format_string,Args &&)" in summary model. |
| Dubious signature "(forward_list &&)" in summary model. |
| Dubious signature "(forward_list &&,const Allocator &)" in summary model. |
| Dubious signature "(list &&)" in summary model. |

View File

@@ -1,4 +1,4 @@
#include "stl.h"
typedef unsigned long size_t;
typedef struct {} FILE;
@@ -157,3 +157,11 @@ void test2()
sink(s[strlen(s) - 1]); // $ ast,ir
sink(ws + (wcslen(ws) / 2)); // $ ast,ir
}
void test_format() {
auto s = std::format("{}", string::source());
sink(s); // $ ir MISSING: ast
auto s2 = std::format(string::source());
sink(s2); // $ ir MISSING: ast
}

View File

@@ -447,6 +447,10 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
| format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT |
| format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT |
| format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT |
| format.cpp:162:12:162:22 | call to format | format.cpp:163:8:163:8 | s | |
| format.cpp:162:24:162:27 | {} | format.cpp:162:24:162:27 | call to basic_format_string | TAINT |
| format.cpp:165:13:165:23 | call to format | format.cpp:166:8:166:9 | s2 | |
| format.cpp:165:25:165:38 | call to source | format.cpp:165:25:165:40 | call to basic_format_string | TAINT |
| map.cpp:21:28:21:28 | call to pair | map.cpp:23:2:23:2 | a | |
| map.cpp:21:28:21:28 | call to pair | map.cpp:24:7:24:7 | a | |
| map.cpp:21:28:21:28 | call to pair | map.cpp:25:7:25:7 | a | |

View File

@@ -642,3 +642,38 @@ namespace std {
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
};
}
// --- string view ---
namespace std {
template<class CharT, class Traits = char_traits<CharT>>
class basic_string_view {
public:
using size_type = size_t;
basic_string_view() noexcept;
basic_string_view(const basic_string_view&) noexcept;
basic_string_view(const CharT*, size_type);
basic_string_view(const CharT*);
template<class It, class End> basic_string_view(It, End);
template<class R> explicit basic_string_view(R&&);
basic_string_view& operator=(const basic_string_view&) noexcept;
};
using string_view = basic_string_view<char>;
}
// --- format ---
namespace std {
template<class CharT /* class... Args */>
struct basic_format_string {
public:
template<class T> basic_format_string(const T&);
basic_string_view<CharT> get() const noexcept;
};
using format_string = basic_format_string<char>; // simplified from `char, std::type_identity_t<Args>...`
template<class... Args> string format( format_string fmt, Args&&... args );
}

View File

@@ -27,6 +27,10 @@ signatureMatches
| stl.h:190:17:190:23 | replace | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 0 |
| stl.h:190:17:190:23 | replace | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 1 |
| stl.h:190:17:190:23 | replace | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | deque | insert<InputIt> | 2 |
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | forward_list | insert_after<InputIt> | 2 |
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | list | insert<InputIt> | 2 |
| stl.h:232:84:232:90 | getline | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
| stl.h:294:12:294:17 | vector | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
| stl.h:294:12:294:17 | vector | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
| stl.h:294:12:294:17 | vector | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
@@ -175,6 +179,7 @@ signatureMatches
| stl.h:333:42:333:47 | insert | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 1 |
| stl.h:333:42:333:47 | insert | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
| stl.h:333:42:333:47 | insert | (const_iterator,InputIt,InputIt) | vector | insert<InputIt> | 2 |
| stl.h:335:37:335:43 | emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:396:3:396:3 | pair | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
| stl.h:396:3:396:3 | pair | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
| stl.h:396:3:396:3 | pair | (const deque &,const Allocator &) | deque<T,Allocator> | deque | 1 |
@@ -215,6 +220,19 @@ signatureMatches
| stl.h:396:3:396:3 | pair | (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 |
| stl.h:396:3:396:3 | pair | (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 |
| stl.h:396:3:396:3 | pair | (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 |
| stl.h:440:36:440:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:440:36:440:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:448:48:448:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:448:48:448:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:452:42:452:57 | insert_or_assign | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:508:36:508:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:508:36:508:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:516:48:516:58 | try_emplace | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:520:42:520:57 | insert_or_assign | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | deque | assign<InputIt> | 0 |
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | deque | assign<InputIt> | 1 |
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | forward_list | assign<InputIt> | 0 |
@@ -223,6 +241,8 @@ signatureMatches
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | list | assign<InputIt> | 1 |
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | vector | assign<InputIt> | 0 |
| stl.h:557:33:557:35 | set | (InputIt,InputIt) | vector | assign<InputIt> | 1 |
| stl.h:569:36:569:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:569:36:569:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 0 |
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 1 |
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | forward_list | assign<InputIt> | 0 |
@@ -231,6 +251,8 @@ signatureMatches
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | list | assign<InputIt> | 1 |
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 0 |
| stl.h:574:38:574:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 1 |
| stl.h:623:36:623:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:623:36:623:47 | emplace_hint | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 0 |
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | deque | assign<InputIt> | 1 |
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | forward_list | assign<InputIt> | 0 |
@@ -239,6 +261,10 @@ signatureMatches
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | list | assign<InputIt> | 1 |
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 0 |
| stl.h:628:38:628:43 | insert | (InputIt,InputIt) | vector | assign<InputIt> | 1 |
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 0 |
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 0 |
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 1 |
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 1 |
getSignatureParameterName
| (InputIt,InputIt) | deque | assign<InputIt> | 0 | func:0 |
| (InputIt,InputIt) | deque | assign<InputIt> | 1 | func:0 |
@@ -315,6 +341,8 @@ getSignatureParameterName
| (deque &&) | deque | deque | 0 | deque && |
| (deque &&,const Allocator &) | deque<T,Allocator> | deque | 0 | deque && |
| (deque &&,const Allocator &) | deque<T,Allocator> | deque | 1 | const class:1 & |
| (format_string,Args &&) | | format<Args> | 0 | format_string |
| (format_string,Args &&) | | format<Args> | 1 | func:0 && |
| (forward_list &&) | forward_list | forward_list | 0 | forward_list && |
| (forward_list &&,const Allocator &) | forward_list<T,Allocator> | forward_list | 0 | forward_list && |
| (forward_list &&,const Allocator &) | forward_list<T,Allocator> | forward_list | 1 | const class:1 & |
@@ -345,6 +373,14 @@ getSignatureParameterName
| (vector &&,const Allocator &) | vector<T,Allocator> | vector | 0 | vector && |
| (vector &&,const Allocator &) | vector<T,Allocator> | vector | 1 | const class:1 & |
getParameterTypeName
| smart_pointer.cpp:7:27:7:30 | sink | 0 | shared_ptr & |
| smart_pointer.cpp:7:27:7:30 | sink | 0 | shared_ptr & |
| smart_pointer.cpp:8:27:8:30 | sink | 0 | unique_ptr & |
| smart_pointer.cpp:8:27:8:30 | sink | 0 | unique_ptr & |
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
| stl.h:29:34:29:40 | forward | 0 | remove_reference_t & |
| stl.h:49:3:49:10 | iterator | 0 | const iterator & |
| stl.h:49:3:49:10 | iterator | 0 | const iterator & |
| stl.h:49:3:49:10 | iterator | 0 | const iterator & |
@@ -377,6 +413,8 @@ getParameterTypeName
| stl.h:88:25:88:33 | operator= | 0 | value_type && |
| stl.h:91:24:91:33 | operator++ | 0 | int |
| stl.h:91:24:91:33 | operator++ | 0 | int |
| stl.h:95:44:95:44 | back_inserter | 0 | func:0 & |
| stl.h:95:44:95:44 | back_inserter | 0 | func:0 & |
| stl.h:148:3:148:14 | basic_string | 0 | const class:2 & |
| stl.h:149:33:149:44 | basic_string | 0 | const class:0 * |
| stl.h:149:33:149:44 | basic_string | 1 | const class:2 & |
@@ -425,6 +463,10 @@ getParameterTypeName
| stl.h:193:8:193:12 | clear | 2 | size_type |
| stl.h:195:8:195:11 | swap | 0 | size_type |
| stl.h:195:8:195:11 | swap | 1 | size_type |
| stl.h:198:94:198:102 | operator+ | 0 | const basic_string & |
| stl.h:198:94:198:102 | operator+ | 1 | const basic_string & |
| stl.h:199:94:199:102 | operator+ | 0 | const basic_string & |
| stl.h:199:94:199:102 | operator+ | 1 | const func:0 * |
| stl.h:214:33:214:42 | operator>> | 0 | int & |
| stl.h:217:33:217:35 | get | 0 | char_type & |
| stl.h:218:33:218:35 | get | 0 | char_type * |
@@ -439,10 +481,23 @@ getParameterTypeName
| stl.h:226:32:226:38 | getline | 0 | char_type * |
| stl.h:226:32:226:38 | getline | 1 | streamsize |
| stl.h:226:32:226:38 | getline | 2 | char_type |
| stl.h:229:68:229:77 | operator>> | 0 | basic_istream & |
| stl.h:229:68:229:77 | operator>> | 1 | func:0 * |
| stl.h:230:85:230:94 | operator>> | 0 | basic_istream & |
| stl.h:230:85:230:94 | operator>> | 1 | basic_string & |
| stl.h:232:84:232:90 | getline | 0 | basic_istream & |
| stl.h:232:84:232:90 | getline | 1 | basic_string & |
| stl.h:232:84:232:90 | getline | 2 | func:0 |
| stl.h:233:84:233:90 | getline | 0 | basic_istream & |
| stl.h:233:84:233:90 | getline | 1 | basic_string & |
| stl.h:240:33:240:42 | operator<< | 0 | int |
| stl.h:242:33:242:35 | put | 0 | char_type |
| stl.h:243:33:243:37 | write | 0 | const char_type * |
| stl.h:243:33:243:37 | write | 1 | streamsize |
| stl.h:247:67:247:76 | operator<< | 0 | basic_ostream & |
| stl.h:247:67:247:76 | operator<< | 1 | const func:0 * |
| stl.h:248:85:248:94 | operator<< | 0 | basic_ostream & |
| stl.h:248:85:248:94 | operator<< | 1 | const basic_string & |
| stl.h:259:12:259:29 | basic_stringstream | 0 | const basic_string & |
| stl.h:263:23:263:31 | operator= | 0 | basic_stringstream && |
| stl.h:265:8:265:11 | swap | 0 | basic_stringstream & |
@@ -496,11 +551,20 @@ getParameterTypeName
| stl.h:333:42:333:47 | insert | 1 | func:0 |
| stl.h:333:42:333:47 | insert | 2 | func:0 |
| stl.h:333:42:333:47 | insert | 2 | func:0 |
| stl.h:335:37:335:43 | emplace | 0 | const_iterator |
| stl.h:335:37:335:43 | emplace | 1 | func:0 && |
| stl.h:336:33:336:44 | emplace_back | 0 | func:0 && |
| stl.h:338:8:338:11 | swap | 0 | vector & |
| stl.h:351:12:351:21 | shared_ptr | 0 | class:0 * |
| stl.h:352:3:352:12 | shared_ptr | 0 | const shared_ptr & |
| stl.h:352:3:352:12 | shared_ptr | 0 | const shared_ptr & |
| stl.h:369:12:369:21 | unique_ptr | 0 | class:0 * |
| stl.h:380:52:380:62 | make_unique | 0 | func:1 && |
| stl.h:380:52:380:62 | make_unique | 0 | func:1 && |
| stl.h:380:52:380:62 | make_unique | 0 | func:1 && |
| stl.h:382:52:382:62 | make_shared | 0 | func:1 && |
| stl.h:382:52:382:62 | make_shared | 0 | func:1 && |
| stl.h:382:52:382:62 | make_shared | 0 | func:1 && |
| stl.h:396:3:396:3 | pair | 0 | const class:0 & |
| stl.h:396:3:396:3 | pair | 0 | const class:0 & |
| stl.h:396:3:396:3 | pair | 0 | const class:0 & |
@@ -524,14 +588,42 @@ getParameterTypeName
| stl.h:397:30:397:33 | pair | 0 | const pair & |
| stl.h:397:30:397:33 | pair | 0 | const pair & |
| stl.h:399:8:399:11 | swap | 0 | pair & |
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
| stl.h:402:72:402:72 | make_pair | 0 | func:0 && |
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
| stl.h:402:72:402:72 | make_pair | 1 | func:1 && |
| stl.h:422:3:422:5 | map | 0 | const map & |
| stl.h:426:8:426:16 | operator= | 0 | const map & |
| stl.h:435:6:435:15 | operator[] | 0 | key_type && |
| stl.h:435:6:435:15 | operator[] | 0 | key_type && |
| stl.h:436:6:436:7 | at | 0 | const key_type & |
| stl.h:439:48:439:54 | emplace | 0 | func:0 && |
| stl.h:439:48:439:54 | emplace | 0 | func:0 && |
| stl.h:440:36:440:47 | emplace_hint | 0 | const_iterator |
| stl.h:440:36:440:47 | emplace_hint | 0 | const_iterator |
| stl.h:440:36:440:47 | emplace_hint | 1 | func:0 && |
| stl.h:440:36:440:47 | emplace_hint | 1 | func:0 && |
| stl.h:443:24:443:29 | insert | 0 | value_type && |
| stl.h:445:12:445:17 | insert | 0 | const_iterator |
| stl.h:445:12:445:17 | insert | 1 | value_type && |
| stl.h:448:48:448:58 | try_emplace | 0 | key_type && |
| stl.h:448:48:448:58 | try_emplace | 0 | key_type && |
| stl.h:448:48:448:58 | try_emplace | 1 | func:0 && |
| stl.h:448:48:448:58 | try_emplace | 1 | func:0 && |
| stl.h:450:36:450:46 | try_emplace | 0 | const_iterator |
| stl.h:450:36:450:46 | try_emplace | 0 | const_iterator |
| stl.h:450:36:450:46 | try_emplace | 1 | key_type && |
| stl.h:450:36:450:46 | try_emplace | 1 | key_type && |
| stl.h:450:36:450:46 | try_emplace | 2 | func:0 && |
| stl.h:450:36:450:46 | try_emplace | 2 | func:0 && |
| stl.h:452:42:452:57 | insert_or_assign | 0 | key_type && |
| stl.h:452:42:452:57 | insert_or_assign | 1 | func:0 && |
| stl.h:454:30:454:45 | insert_or_assign | 0 | const_iterator |
@@ -550,9 +642,34 @@ getParameterTypeName
| stl.h:503:16:503:25 | operator[] | 0 | key_type && |
| stl.h:503:16:503:25 | operator[] | 0 | key_type && |
| stl.h:504:16:504:17 | at | 0 | const key_type & |
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
| stl.h:507:48:507:54 | emplace | 0 | func:0 && |
| stl.h:508:36:508:47 | emplace_hint | 0 | const_iterator |
| stl.h:508:36:508:47 | emplace_hint | 0 | const_iterator |
| stl.h:508:36:508:47 | emplace_hint | 1 | func:0 && |
| stl.h:508:36:508:47 | emplace_hint | 1 | func:0 && |
| stl.h:511:24:511:29 | insert | 0 | value_type && |
| stl.h:513:12:513:17 | insert | 0 | const_iterator |
| stl.h:513:12:513:17 | insert | 1 | value_type && |
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
| stl.h:516:48:516:58 | try_emplace | 0 | key_type && |
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
| stl.h:516:48:516:58 | try_emplace | 1 | func:0 && |
| stl.h:518:36:518:46 | try_emplace | 0 | const_iterator |
| stl.h:518:36:518:46 | try_emplace | 0 | const_iterator |
| stl.h:518:36:518:46 | try_emplace | 1 | key_type && |
| stl.h:518:36:518:46 | try_emplace | 1 | key_type && |
| stl.h:518:36:518:46 | try_emplace | 2 | func:0 && |
| stl.h:518:36:518:46 | try_emplace | 2 | func:0 && |
| stl.h:520:42:520:57 | insert_or_assign | 0 | key_type && |
| stl.h:520:42:520:57 | insert_or_assign | 1 | func:0 && |
| stl.h:522:30:522:45 | insert_or_assign | 0 | const_iterator |
@@ -567,6 +684,12 @@ getParameterTypeName
| stl.h:557:33:557:35 | set | 0 | func:0 |
| stl.h:557:33:557:35 | set | 1 | func:0 |
| stl.h:560:8:560:16 | operator= | 0 | const set & |
| stl.h:568:48:568:54 | emplace | 0 | func:0 && |
| stl.h:568:48:568:54 | emplace | 0 | func:0 && |
| stl.h:569:36:569:47 | emplace_hint | 0 | const_iterator |
| stl.h:569:36:569:47 | emplace_hint | 0 | const_iterator |
| stl.h:569:36:569:47 | emplace_hint | 1 | func:0 && |
| stl.h:569:36:569:47 | emplace_hint | 1 | func:0 && |
| stl.h:571:23:571:28 | insert | 0 | value_type && |
| stl.h:573:12:573:17 | insert | 0 | const_iterator |
| stl.h:573:12:573:17 | insert | 1 | value_type && |
@@ -584,6 +707,12 @@ getParameterTypeName
| stl.h:611:33:611:45 | unordered_set | 1 | func:0 |
| stl.h:611:33:611:45 | unordered_set | 2 | size_type |
| stl.h:614:18:614:26 | operator= | 0 | const unordered_set & |
| stl.h:622:48:622:54 | emplace | 0 | func:0 && |
| stl.h:622:48:622:54 | emplace | 0 | func:0 && |
| stl.h:623:36:623:47 | emplace_hint | 0 | const_iterator |
| stl.h:623:36:623:47 | emplace_hint | 0 | const_iterator |
| stl.h:623:36:623:47 | emplace_hint | 1 | func:0 && |
| stl.h:623:36:623:47 | emplace_hint | 1 | func:0 && |
| stl.h:625:24:625:29 | insert | 0 | value_type && |
| stl.h:627:12:627:17 | insert | 0 | const_iterator |
| stl.h:627:12:627:17 | insert | 1 | value_type && |
@@ -594,3 +723,18 @@ getParameterTypeName
| stl.h:636:37:636:41 | merge | 0 | unordered_set & |
| stl.h:639:12:639:15 | find | 0 | const key_type & |
| stl.h:641:28:641:38 | equal_range | 0 | const key_type & |
| stl.h:671:21:671:39 | basic_format_string | 0 | const func:0 & |
| stl.h:671:21:671:39 | basic_format_string | 0 | const func:0 & |
| stl.h:678:33:678:38 | format | 0 | format_string |
| stl.h:678:33:678:38 | format | 0 | format_string |
| stl.h:678:33:678:38 | format | 1 | func:0 && |
| stl.h:678:33:678:38 | format | 1 | func:0 && |
| stringstream.cpp:18:6:18:9 | sink | 0 | const basic_ostream> & |
| stringstream.cpp:21:6:21:9 | sink | 0 | const basic_istream> & |
| stringstream.cpp:24:6:24:9 | sink | 0 | const basic_iostream> & |
| swap1.cpp:14:9:14:9 | move | 0 | func:0 & |
| swap2.cpp:14:9:14:9 | move | 0 | func:0 & |
| swap.h:4:20:4:23 | swap | 0 | func:0 & |
| swap.h:4:20:4:23 | swap | 1 | func:0 & |
| vector.cpp:14:27:14:30 | sink | 0 | vector> & |
| vector.cpp:14:27:14:30 | sink | 0 | vector> & |

View File

@@ -0,0 +1,5 @@
import cpp
from DeductionGuide d
where not exists(d.getTemplateClass())
select d

View File

@@ -0,0 +1,5 @@
| file://:0:0:0:0 | C | test.cpp:4:8:4:8 | C<T> |
| file://:0:0:0:0 | C | test.cpp:4:8:4:8 | C<T> |
| test.cpp:5:5:5:5 | (unnamed deduction guide) | test.cpp:4:8:4:8 | C<T> |
| test.cpp:6:5:6:5 | (unnamed deduction guide) | test.cpp:4:8:4:8 | C<T> |
| test.cpp:12:1:12:1 | C | test.cpp:4:8:4:8 | C<T> |

View File

@@ -0,0 +1,4 @@
import cpp
from DeductionGuide d
select d, d.getTemplateClass()

View File

@@ -0,0 +1,21 @@
// semmle-extractor-options: -std=c++20
template<typename T>
struct C {
C(const T);
C(char, char);
};
C(const double) -> C<int>;
template<typename T>
C(const T) -> C<int>;
C(char, char) -> C<char>;
void test() {
new C<char>(0);
new C<int>(0);
new C(0.0f);
new C(0.0);
}

View File

@@ -62,3 +62,9 @@ Virtual getAVirtual();
void test9() {
typeid(getAVirtual()); // unevaluated
}
void constExprIf() {
if constexpr(sizeof(int) == 4) { } // unevaluated
}
// semmle-extractor-options: -std=c++20

View File

@@ -14,3 +14,7 @@
| test.cpp:57:9:57:9 | 4 |
| test.cpp:63:9:63:19 | call to getAVirtual |
| test.cpp:63:9:63:21 | temporary object |
| test.cpp:67:16:67:26 | sizeof(int) |
| test.cpp:67:16:67:31 | ... == ... |
| test.cpp:67:31:67:31 | 4 |
| test.cpp:67:31:67:31 | (unsigned long)... |

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@ missingOperand
unexpectedOperand
duplicateOperand
missingPhiOperand
| ir.cpp:2670:3:2670:9 | Phi: call to use_int | Instruction 'Phi: call to use_int' is missing an operand for predecessor block 'EnterFunction: phi_with_single_input_at_merge' in function '$@'. | ir.cpp:2663:13:2663:42 | void phi_with_single_input_at_merge(bool) | void phi_with_single_input_at_merge(bool) |
missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary

Some files were not shown because too many files have changed in this diff Show More