mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge branch 'main' into jcogs33/java/add-apache-ant-path-inj-sinks
This commit is contained in:
2296
cpp/downgrades/25e365d1e8147df0f759b604f96eb4bffea48271/old.dbscheme
Normal file
2296
cpp/downgrades/25e365d1e8147df0f759b604f96eb4bffea48271/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
description: Revert support for using-enum declarations.
|
||||
compatibility: partial
|
||||
usings.rel: run usings.qlo
|
||||
using_container.rel: run using_container.qlo
|
||||
@@ -0,0 +1,14 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element parent, int kind
|
||||
where
|
||||
usings(u, _, _, kind) and
|
||||
using_container(parent, u) and
|
||||
kind != 3
|
||||
select parent, u
|
||||
@@ -0,0 +1,17 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element target, Location loc, int kind
|
||||
where
|
||||
usings(u, target, loc, kind) and
|
||||
kind != 3
|
||||
select u, target, loc
|
||||
2300
cpp/downgrades/9629fc87dab7dbed0771bf5ce22bce4d7f943b52/old.dbscheme
Normal file
2300
cpp/downgrades/9629fc87dab7dbed0771bf5ce22bce4d7f943b52/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support destroying deletes
|
||||
compatibility: full
|
||||
@@ -1,3 +1,11 @@
|
||||
## 1.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.
|
||||
* Added subclasses of `BuiltInOperations` for `__builtin_has_attribute`, `__builtin_is_corresponding_member`, `__builtin_is_pointer_interconvertible_with_class`, `__is_assignable_no_precondition_check`, `__is_bounded_array`, `__is_convertible`, `__is_corresponding_member`, `__is_nothrow_convertible`, `__is_pointer_interconvertible_with_class`, `__is_referenceable`, `__is_same_as`, `__is_trivially_copy_assignable`, `__is_unbounded_array`, `__is_valid_winrt_type`, `_is_win_class`, `__is_win_interface`, `__reference_binds_to_temporary`, `__reference_constructs_from_temporary`, and `__reference_converts_from_temporary`.
|
||||
* The class `NewArrayExpr` adds a predicate `getArraySize()` to allow a more convenient way to access the static size of the array when the extent is missing.
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* The class `NewArrayExpr` adds a predicate `getArraySize()` to allow a more convenient way to access the static size of the array when the extent is missing.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
|
||||
@@ -1,4 +1,7 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
## 1.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.
|
||||
* Added subclasses of `BuiltInOperations` for `__builtin_has_attribute`, `__builtin_is_corresponding_member`, `__builtin_is_pointer_interconvertible_with_class`, `__is_assignable_no_precondition_check`, `__is_bounded_array`, `__is_convertible`, `__is_corresponding_member`, `__is_nothrow_convertible`, `__is_pointer_interconvertible_with_class`, `__is_referenceable`, `__is_same_as`, `__is_trivially_copy_assignable`, `__is_unbounded_array`, `__is_valid_winrt_type`, `_is_win_class`, `__is_win_interface`, `__reference_binds_to_temporary`, `__reference_constructs_from_temporary`, and `__reference_converts_from_temporary`.
|
||||
* The class `NewArrayExpr` adds a predicate `getArraySize()` to allow a more convenient way to access the static size of the array when the extent is missing.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.2.0
|
||||
lastReleaseVersion: 1.3.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 1.2.1-dev
|
||||
version: 1.3.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -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()`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -855,6 +855,16 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the deallocation function is a destroying delete.
|
||||
*/
|
||||
predicate isDestroyingDeleteDeallocation() {
|
||||
exists(int form |
|
||||
expr_deallocator(underlyingElement(this), _, form) and
|
||||
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type that is being allocated.
|
||||
*
|
||||
@@ -1025,6 +1035,16 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the deallocation function is a destroying delete.
|
||||
*/
|
||||
predicate isDestroyingDeleteDeallocation() {
|
||||
exists(int form |
|
||||
expr_deallocator(underlyingElement(this), _, form) and
|
||||
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object or array being deleted.
|
||||
*/
|
||||
|
||||
@@ -994,9 +994,6 @@ DataFlowType getNodeType(Node n) {
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(DataFlowType t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
@@ -1097,7 +1094,11 @@ class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
final private class TypeFinal = Type;
|
||||
|
||||
class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
|
||||
@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
not instr.isResultModeled()
|
||||
}
|
||||
|
||||
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
|
||||
private predicate consumedAsAddressOperand(Operand operand) {
|
||||
operand instanceof AddressOperand
|
||||
or
|
||||
exists(Operand address |
|
||||
consumedAsAddressOperand(address) and
|
||||
operandIsPropagated(operand, _, address.getDef())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` may originate from a base instruction of an allocation,
|
||||
* and that operand may transitively flow to an `AddressOperand`.
|
||||
*/
|
||||
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
|
||||
consumedAsAddressOperand(operand) and
|
||||
(
|
||||
not exists(Configuration::getOldAllocation(allocation)) and
|
||||
operand.getDef() = allocation.getABaseInstruction()
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromAllocationBase(address, allocation)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate propagatedFromNonAllocationBase(Operand operand) {
|
||||
exists(Instruction def |
|
||||
def = operand.getDef() and
|
||||
not operandIsPropagated(_, _, def) and
|
||||
not def = any(Configuration::Allocation allocation).getABaseInstruction()
|
||||
)
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we cannot see all producers of an operand for which allocation also flows into.
|
||||
*/
|
||||
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
|
||||
exists(AddressOperand address |
|
||||
propagatedFromAllocationBase(address, allocation) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
|
||||
* either because the allocation's address is taken within the function and escapes, or because the
|
||||
@@ -346,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
allocation.alwaysEscapes()
|
||||
or
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
or
|
||||
operandConsumesEscaped(allocation)
|
||||
)
|
||||
or
|
||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -146,3 +146,8 @@ class DynamicAllocation extends Allocation, TDynamicAllocation {
|
||||
}
|
||||
|
||||
predicate phaseNeedsSoundEscapeAnalysis() { none() }
|
||||
|
||||
UnaliasedSsa::Allocation getOldAllocation(VariableAllocation allocation) {
|
||||
UnaliasedSsa::canReuseSsaForVariable(allocation.getIRVariable()) and
|
||||
result = allocation.getIRVariable()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConst
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import AliasConfiguration
|
||||
import AliasConfiguration
|
||||
private import codeql.util.Boolean
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
@@ -227,13 +227,15 @@ private newtype TMemoryLocation =
|
||||
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
|
||||
|
||||
/**
|
||||
* Represents the memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* one of the following:
|
||||
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
||||
* unknown.
|
||||
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
|
||||
*
|
||||
* Some of these memory locations will be filtered out for performance reasons before being passed to SSA construction.
|
||||
*/
|
||||
abstract class MemoryLocation extends TMemoryLocation {
|
||||
abstract private class MemoryLocation0 extends TMemoryLocation {
|
||||
final string toString() {
|
||||
if this.isMayAccess()
|
||||
then result = "?" + this.toStringInternal()
|
||||
@@ -294,9 +296,9 @@ abstract class MemoryLocation extends TMemoryLocation {
|
||||
* represented by a `MemoryLocation` that totally overlaps all other
|
||||
* `MemoryLocations` in the set.
|
||||
*/
|
||||
abstract class VirtualVariable extends MemoryLocation { }
|
||||
abstract class VirtualVariable extends MemoryLocation0 { }
|
||||
|
||||
abstract class AllocationMemoryLocation extends MemoryLocation {
|
||||
abstract class AllocationMemoryLocation extends MemoryLocation0 {
|
||||
Allocation var;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -424,7 +426,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
|
||||
* `{a, b}` into a memory location that represents _all_ of the allocations
|
||||
* in the set.
|
||||
*/
|
||||
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation {
|
||||
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation0 {
|
||||
VariableGroup vg;
|
||||
boolean isMayAccess;
|
||||
boolean isAll;
|
||||
@@ -528,7 +530,7 @@ class GroupedVirtualVariable extends GroupedMemoryLocation, VirtualVariable {
|
||||
/**
|
||||
* An access to memory that is not known to be confined to a specific `IRVariable`.
|
||||
*/
|
||||
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
|
||||
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -555,7 +557,7 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
|
||||
* An access to memory that is not known to be confined to a specific `IRVariable`, but is known to
|
||||
* not access memory on the current function's stack frame.
|
||||
*/
|
||||
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
||||
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -589,7 +591,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
||||
/**
|
||||
* An access to all aliased memory.
|
||||
*/
|
||||
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
|
||||
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -620,7 +622,7 @@ class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
|
||||
/**
|
||||
* Gets the overlap relationship between the definition location `def` and the use location `use`.
|
||||
*/
|
||||
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
Overlap getOverlap(MemoryLocation0 def, MemoryLocation0 use) {
|
||||
exists(Overlap overlap |
|
||||
// Compute the overlap based only on the extent.
|
||||
overlap = getExtentOverlap(def, use) and
|
||||
@@ -648,7 +650,7 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
* based only on the set of memory locations accessed. Handling of "may" accesses and read-only
|
||||
* locations occurs in `getOverlap()`.
|
||||
*/
|
||||
private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
|
||||
// The def and the use must have the same virtual variable, or no overlap is possible.
|
||||
(
|
||||
// AllAliasedMemory must totally overlap any location within the same virtual variable.
|
||||
@@ -861,6 +863,40 @@ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMem
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/** Gets the number of overlapping uses of `def`. */
|
||||
private int numberOfOverlappingUses(MemoryLocation0 def) {
|
||||
result = strictcount(MemoryLocation0 use | exists(getOverlap(def, use)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is a busy definition. That is, it has a large number of
|
||||
* overlapping uses.
|
||||
*/
|
||||
private predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
|
||||
|
||||
/** Holds if `use` is a use that overlaps with a busy definition. */
|
||||
private predicate useOverlapWithBusyDef(MemoryLocation0 use) {
|
||||
exists(MemoryLocation0 def |
|
||||
exists(getOverlap(def, use)) and
|
||||
isBusyDef(def)
|
||||
)
|
||||
}
|
||||
|
||||
final private class FinalMemoryLocation = MemoryLocation0;
|
||||
|
||||
/**
|
||||
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* one of the following:
|
||||
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
||||
* unknown.
|
||||
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
|
||||
*
|
||||
* Compared to `MemoryLocation0`, this class does not contain memory locations that represent uses of busy definitions.
|
||||
*/
|
||||
class MemoryLocation extends FinalMemoryLocation {
|
||||
MemoryLocation() { not useOverlapWithBusyDef(this) }
|
||||
}
|
||||
|
||||
MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
not canReuseSsaForOldResult(instr) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
@@ -905,9 +941,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
)
|
||||
}
|
||||
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
private MemoryLocation0 getOperandMemoryLocation0(MemoryOperand operand, boolean isMayAccess) {
|
||||
not canReuseSsaForOldResult(operand.getAnyDef()) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
exists(MemoryAccessKind kind |
|
||||
kind = operand.getMemoryAccess() and
|
||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
(
|
||||
@@ -948,6 +984,19 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
)
|
||||
}
|
||||
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
exists(MemoryLocation0 use0, boolean isMayAccess |
|
||||
use0 = getOperandMemoryLocation0(operand, isMayAccess)
|
||||
|
|
||||
result = use0
|
||||
or
|
||||
// If `use0` overlaps with a busy definition we turn it into a use
|
||||
// of `UnknownMemoryLocation`.
|
||||
not use0 instanceof MemoryLocation and
|
||||
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||
int getStartBitOffset(VariableMemoryLocation location) {
|
||||
result = location.getStartBitOffset() and Ints::hasValue(result)
|
||||
|
||||
@@ -933,11 +933,15 @@ module DefUse {
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getNonChiOffset(int index, OldBlock block) {
|
||||
exists(IRFunction func | func = block.getEnclosingIRFunction() |
|
||||
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
|
||||
func = block.getEnclosingIRFunction() and
|
||||
i = block.getInstruction(index) and
|
||||
entryBlock = func.getEntryBlock()
|
||||
|
|
||||
if
|
||||
getNewBlock(block) = func.getEntryBlock() and
|
||||
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
|
||||
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
|
||||
block = entryBlock and
|
||||
not i instanceof InitializeNonLocalInstruction and
|
||||
not i instanceof AliasedDefinitionInstruction
|
||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||
else result = 2 * index
|
||||
)
|
||||
|
||||
@@ -338,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
not instr.isResultModeled()
|
||||
}
|
||||
|
||||
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
|
||||
private predicate consumedAsAddressOperand(Operand operand) {
|
||||
operand instanceof AddressOperand
|
||||
or
|
||||
exists(Operand address |
|
||||
consumedAsAddressOperand(address) and
|
||||
operandIsPropagated(operand, _, address.getDef())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` may originate from a base instruction of an allocation,
|
||||
* and that operand may transitively flow to an `AddressOperand`.
|
||||
*/
|
||||
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
|
||||
consumedAsAddressOperand(operand) and
|
||||
(
|
||||
not exists(Configuration::getOldAllocation(allocation)) and
|
||||
operand.getDef() = allocation.getABaseInstruction()
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromAllocationBase(address, allocation)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate propagatedFromNonAllocationBase(Operand operand) {
|
||||
exists(Instruction def |
|
||||
def = operand.getDef() and
|
||||
not operandIsPropagated(_, _, def) and
|
||||
not def = any(Configuration::Allocation allocation).getABaseInstruction()
|
||||
)
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we cannot see all producers of an operand for which allocation also flows into.
|
||||
*/
|
||||
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
|
||||
exists(AddressOperand address |
|
||||
propagatedFromAllocationBase(address, allocation) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
|
||||
* either because the allocation's address is taken within the function and escapes, or because the
|
||||
@@ -346,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
allocation.alwaysEscapes()
|
||||
or
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
or
|
||||
operandConsumesEscaped(allocation)
|
||||
)
|
||||
or
|
||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
private import AliasConfigurationImports
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A memory allocation that can be tracked by the SimpleSSA alias analysis.
|
||||
@@ -16,3 +17,5 @@ class Allocation extends IRAutomaticVariable {
|
||||
}
|
||||
|
||||
predicate phaseNeedsSoundEscapeAnalysis() { any() }
|
||||
|
||||
Unit getOldAllocation(Allocation allocation) { any() }
|
||||
|
||||
@@ -933,11 +933,15 @@ module DefUse {
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getNonChiOffset(int index, OldBlock block) {
|
||||
exists(IRFunction func | func = block.getEnclosingIRFunction() |
|
||||
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
|
||||
func = block.getEnclosingIRFunction() and
|
||||
i = block.getInstruction(index) and
|
||||
entryBlock = func.getEntryBlock()
|
||||
|
|
||||
if
|
||||
getNewBlock(block) = func.getEntryBlock() and
|
||||
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
|
||||
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
|
||||
block = entryBlock and
|
||||
not i instanceof InitializeNonLocalInstruction and
|
||||
not i instanceof AliasedDefinitionInstruction
|
||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||
else result = 2 * index
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import AliasAnalysis
|
||||
private import SimpleSSAImports
|
||||
import SimpleSSAPublicImports
|
||||
private import AliasConfiguration
|
||||
import AliasConfiguration
|
||||
private import codeql.util.Unit
|
||||
|
||||
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
|
||||
|
||||
@@ -27,6 +27,11 @@ private import implementations.StdPair
|
||||
private import implementations.StdMap
|
||||
private import implementations.StdSet
|
||||
private import implementations.StdString
|
||||
private import implementations.StdFunction
|
||||
private import implementations.StdException
|
||||
private import implementations.StdAllocator
|
||||
private import implementations.StdAlgorithm
|
||||
private import implementations.StdMath
|
||||
private import implementations.Swap
|
||||
private import implementations.GetDelim
|
||||
private import implementations.SmartPointer
|
||||
|
||||
@@ -86,6 +86,41 @@ private class StdIterator extends Iterator, Class {
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdReverseIterator extends Iterator, Class {
|
||||
StdReverseIterator() { this.hasQualifiedName(["std", "bsl"], "reverse_iterator") }
|
||||
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdIstreamBufIterator extends Iterator, Class {
|
||||
StdIstreamBufIterator() { this.hasQualifiedName(["std", "bsl"], "istreambuf_iterator") }
|
||||
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdIstreambufIteratorConstructor extends Constructor, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdIstreambufIteratorConstructor() { this.getDeclaringType() instanceof StdIstreamBufIterator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `FunctionInput` corresponding to an iterator parameter to
|
||||
* user-defined operator `op`, at `index`.
|
||||
@@ -579,23 +614,43 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
|
||||
}
|
||||
|
||||
private string beginName() {
|
||||
result = ["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]
|
||||
}
|
||||
|
||||
/**
|
||||
* A `begin` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class BeginFunction extends MemberFunction {
|
||||
class BeginFunction extends Function {
|
||||
BeginFunction() {
|
||||
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this.getUnspecifiedType() instanceof Iterator and
|
||||
(
|
||||
this.hasName(beginName()) and
|
||||
this instanceof MemberFunction
|
||||
or
|
||||
this.hasGlobalOrStdOrBslName(beginName()) and
|
||||
not this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private string endName() { result = ["end", "cend", "rend", "crend"] }
|
||||
|
||||
/**
|
||||
* An `end` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class EndFunction extends MemberFunction {
|
||||
class EndFunction extends Function {
|
||||
EndFunction() {
|
||||
this.hasName(["end", "cend", "rend", "crend"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this.getUnspecifiedType() instanceof Iterator and
|
||||
(
|
||||
this.hasName(endName()) and
|
||||
this instanceof MemberFunction
|
||||
or
|
||||
this.hasGlobalOrStdOrBslName(endName()) and
|
||||
this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,7 +658,7 @@ class EndFunction extends MemberFunction {
|
||||
* A `begin` or `end` member function, or a related member function, that
|
||||
* returns an iterator.
|
||||
*/
|
||||
class BeginOrEndFunction extends MemberFunction {
|
||||
class BeginOrEndFunction extends Function {
|
||||
BeginOrEndFunction() {
|
||||
this instanceof BeginFunction or
|
||||
this instanceof EndFunction
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||
@@ -96,7 +97,7 @@ private class Sprintf extends FormattingFunction {
|
||||
/**
|
||||
* Implements `Snprintf`.
|
||||
*/
|
||||
private class SnprintfImpl extends Snprintf {
|
||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
|
||||
SnprintfImpl() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -143,6 +144,26 @@ private class SnprintfImpl extends Snprintf {
|
||||
}
|
||||
|
||||
override int getSizeParameterIndex() { result = 1 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
// We don't know how many parameters are passed to the function since it's varargs, but they also don't escape.
|
||||
index = this.getFormatParameterIndex()
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getOutputParameterIndex(false) and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// We don't know how many parameters are passed to the function since it's varargs, but they also have read side effects.
|
||||
i = this.getFormatParameterIndex() and buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Provides models for C++ functions from the `algorithms` header.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class StdPartialSort extends Function, SideEffectFunction, AliasFunction {
|
||||
StdPartialSort() { this.hasGlobalOrStdName("partial_sort") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and
|
||||
buffer = true and
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
index = this.getAnIteratorParameterIndex()
|
||||
or
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdSortHeap extends Function, SideEffectFunction, AliasFunction {
|
||||
StdSortHeap() { this.hasGlobalOrStdName("sort_heap") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdGenerateN extends Function, SideEffectFunction, AliasFunction {
|
||||
StdGenerateN() { this.hasGlobalOrStdName("generate_n") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdFindIfOrIfNot extends Function, SideEffectFunction, AliasFunction {
|
||||
StdFindIfOrIfNot() { this.hasGlobalOrStdName(["find_if", "find_if_not"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true
|
||||
or
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) {
|
||||
index = this.getAnIteratorParameterIndex()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/**
|
||||
* Provides models for C++ `allocator` and `allocator_traits` classes.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/** The `std::allocator` class. */
|
||||
class StdAllocator extends Class {
|
||||
StdAllocator() { this.hasGlobalOrStdOrBslName("allocator") }
|
||||
}
|
||||
|
||||
/** The `std::allocator_traits` class. */
|
||||
class StdAllocatorTraits extends Class {
|
||||
StdAllocatorTraits() { this.hasGlobalOrStdOrBslName("allocator_traits") }
|
||||
}
|
||||
|
||||
private class StdAllocatorConstructor extends Constructor, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorConstructor() { this.getDeclaringType() instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorDestructor extends Destructor, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDestructor() { this.getDeclaringType() instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorAddress extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorAddress() { this.getClassAndName("address") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorAllocate() { this.getClassAndName("allocate") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorTraitsAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsAllocate() {
|
||||
this.getClassAndName(["allocate", "allocate_at_least"]) instanceof StdAllocatorTraits
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorDeallocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDeallocate() { this.getClassAndName("deallocate") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and
|
||||
buffer = false and
|
||||
mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorTraitsDeallocate extends MemberFunction, AliasFunction, SideEffectFunction
|
||||
{
|
||||
StdAllocatorTraitsDeallocate() {
|
||||
this.getClassAndName("deallocate") instanceof StdAllocatorTraits
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and
|
||||
buffer = false and
|
||||
mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorMaxSize() { this.getClassAndName("max_size") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatTraitsMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatTraitsMaxSize() { this.getClassAndName("max_size") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorConstruct() { this.getClassAndName("construct") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorTraitsConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsConstruct() { this.getClassAndName("construct") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
index = 1 or this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDestroy() { this.getClassAndName("destroy") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorTraitsDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsDestroy() { this.getClassAndName("destroy") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* A sequence container template class (for example, `std::vector`) from the
|
||||
@@ -58,7 +60,7 @@ private class Vector extends StdSequenceContainer {
|
||||
/**
|
||||
* The standard container functions `push_back` and `push_front`.
|
||||
*/
|
||||
class StdSequenceContainerPush extends MemberFunction {
|
||||
class StdSequenceContainerPush extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerPush() {
|
||||
this.getClassAndName("push_back") instanceof Vector or
|
||||
this.getClassAndName(["push_back", "push_front"]) instanceof Deque or
|
||||
@@ -74,12 +76,115 @@ class StdSequenceContainerPush extends MemberFunction {
|
||||
this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// the `std::vector<bool>` specialization doesn't take a reference as a
|
||||
// parameter. So we need to check that the parameter is actually a
|
||||
// reference.
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerPopFrontOrBack extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerPopFrontOrBack() {
|
||||
this.getClassAndName("pop_back") instanceof Vector or
|
||||
this.getClassAndName("pop_front") instanceof ForwardList or
|
||||
this.getClassAndName(["pop_front", "pop_back"]) instanceof Deque or
|
||||
this.getClassAndName(["pop_front", "pop_back"]) instanceof List
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerClear extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerClear() {
|
||||
this.getClassAndName("clear") instanceof Vector or
|
||||
this.getClassAndName("clear") instanceof Deque or
|
||||
this.getClassAndName("clear") instanceof ForwardList or
|
||||
this.getClassAndName("clear") instanceof List
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdVectorReserve extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdVectorReserve() { this.getClassAndName("reserve") instanceof Vector }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `insert` and `insert_after`.
|
||||
*/
|
||||
class StdSequenceContainerInsert extends MemberFunction {
|
||||
class StdSequenceContainerInsert extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerInsert() {
|
||||
this.getClassAndName("insert") instanceof Deque or
|
||||
this.getClassAndName("insert") instanceof List or
|
||||
@@ -100,17 +205,138 @@ class StdSequenceContainerInsert extends MemberFunction {
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerFrontBack extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerFrontBack() {
|
||||
this.getClassAndName(["front", "back"]) instanceof Deque or
|
||||
this.getClassAndName(["front", "back"]) instanceof List or
|
||||
this.getClassAndName(["front", "back"]) instanceof Vector or
|
||||
// forward_list does not have a 'back' member function
|
||||
this.getClassAndName("front") instanceof ForwardList
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdSequenceContainerAt extends MemberFunction {
|
||||
class StdSequenceContainerAt extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerAt() {
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Array or
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Deque or
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Vector
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerMemberEquals extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerMemberEquals() {
|
||||
this.getClassAndName("operator==") instanceof Array or
|
||||
this.getClassAndName("operator==") instanceof Deque or
|
||||
this.getClassAndName("operator==") instanceof Vector
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 or index = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
or
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerEquals extends Function, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerEquals() {
|
||||
this.hasGlobalOrStdOrBslName("operator==") and
|
||||
not this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 2 and
|
||||
(
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector
|
||||
or
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List
|
||||
or
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,6 +368,115 @@ class StdVectorEmplace extends StdSequenceEmplace {
|
||||
StdVectorEmplace() { this.getDeclaringType() instanceof Vector }
|
||||
}
|
||||
|
||||
private class StdSequenceSize extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceSize() {
|
||||
this.getClassAndName("size") instanceof Vector
|
||||
or
|
||||
this.getClassAndName("size") instanceof List
|
||||
or
|
||||
this.getClassAndName("size") instanceof Deque
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdSequenceDestructor() {
|
||||
this.getDeclaringType() instanceof Vector
|
||||
or
|
||||
this.getDeclaringType() instanceof List
|
||||
or
|
||||
this.getDeclaringType() instanceof Deque
|
||||
}
|
||||
|
||||
private Destructor getElementDestructor() {
|
||||
result.getDeclaringType() = this.getTemplateArgument(0)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() {
|
||||
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
|
||||
or
|
||||
not exists(this.getElementDestructor())
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
|
||||
or
|
||||
not exists(this.getElementDestructor())
|
||||
}
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdSequenceConstructor() {
|
||||
this.getDeclaringType() instanceof Vector
|
||||
or
|
||||
this.getDeclaringType() instanceof List
|
||||
or
|
||||
this.getDeclaringType() instanceof Deque
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class InitializerList extends Class {
|
||||
InitializerList() { this.hasQualifiedName(["std", "bsl"], "initializer_list") }
|
||||
|
||||
Type getElementType() { result = this.getTemplateArgument(0) }
|
||||
}
|
||||
|
||||
private class InitializerListConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
InitializerListConstructor() { this.getDeclaringType() instanceof InitializerList }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard vector `emplace_back` function.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Provides models for the C++ `std::exception` class and subclasses.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/** The `std::exception` class. */
|
||||
class StdException extends Class {
|
||||
StdException() { this.hasGlobalOrStdOrBslName("exception") }
|
||||
}
|
||||
|
||||
/** The `std::bad_alloc` class. */
|
||||
class StdBadAllocException extends Class {
|
||||
StdBadAllocException() { this.hasGlobalOrStdOrBslName("bad_alloc") }
|
||||
}
|
||||
|
||||
private class StdBadAllocExceptionConstructor extends Constructor, SideEffectFunction, AliasFunction
|
||||
{
|
||||
StdBadAllocExceptionConstructor() { this.getDeclaringType() instanceof StdBadAllocException }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Provides models for C++ `std::function` class.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* An instantiation of the `std::function` class template.
|
||||
*/
|
||||
class StdFunction extends ClassTemplateInstantiation {
|
||||
StdFunction() { this.hasGlobalOrStdOrBslName("function") }
|
||||
}
|
||||
|
||||
private class StdFunctionConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdFunctionConstructor() { this.getDeclaringType() instanceof StdFunction }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdFunctionDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdFunctionDestructor() { this.getDeclaringType() instanceof StdFunction }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* The `std::map` and `std::unordered_map` template classes.
|
||||
@@ -16,7 +18,9 @@ private class MapOrUnorderedMap extends Class {
|
||||
/**
|
||||
* Additional model for map constructors using iterator inputs.
|
||||
*/
|
||||
private class StdMapConstructor extends Constructor, TaintFunction {
|
||||
private class StdMapConstructor extends Constructor, TaintFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
{
|
||||
StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
|
||||
|
||||
/**
|
||||
@@ -35,6 +39,23 @@ private class StdMapConstructor extends Constructor, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +154,7 @@ class StdMapAt extends MemberFunction {
|
||||
StdMapAt() { this.getClassAndName(["at", "operator[]"]) instanceof MapOrUnorderedMap }
|
||||
}
|
||||
|
||||
private class StdMapAtModels extends StdMapAt, TaintFunction {
|
||||
private class StdMapAtModels extends StdMapAt, TaintFunction, AliasFunction, SideEffectFunction {
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
@@ -144,6 +165,18 @@ private class StdMapAtModels extends StdMapAt, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
}
|
||||
|
||||
@@ -187,3 +220,63 @@ private class StdMapEqualRange extends TaintFunction {
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
class StdMapDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdMapDestructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdMapClear extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdMapClear() { this.getClassAndName("clear") instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdMapSize extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdMapSize() { this.getClassAndName("size") instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
108
cpp/ql/lib/semmle/code/cpp/models/implementations/StdMath.qll
Normal file
108
cpp/ql/lib/semmle/code/cpp/models/implementations/StdMath.qll
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Provides models for C++ functions from the `cmath` header.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class LdExp extends Function, SideEffectFunction {
|
||||
LdExp() { this.hasGlobalOrStdOrBslName(["ldexp", "ldexpf", "ldexpl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Abs extends Function, SideEffectFunction {
|
||||
Abs() { this.hasGlobalOrStdOrBslName(["abs", "fabs", "fabsf", "fabsl", "llabs", "imaxabs"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Div extends Function, SideEffectFunction {
|
||||
Div() { this.hasGlobalOrStdOrBslName(["div", "ldiv", "lldiv", "imaxdiv"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class FMod extends Function, SideEffectFunction {
|
||||
FMod() { this.hasGlobalOrStdOrBslName(["fmod", "fmodf", "fmodl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Remainder extends Function, SideEffectFunction {
|
||||
Remainder() { this.hasGlobalOrStdOrBslName(["remainder", "remainderf", "remainderl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Remquo extends Function, SideEffectFunction {
|
||||
Remquo() { this.hasGlobalOrStdOrBslName(["remquo", "remquof", "remquol"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
private class Fma extends Function, SideEffectFunction {
|
||||
Fma() { this.hasGlobalOrStdOrBslName(["fma", "fmaf", "fmal"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fmax extends Function, SideEffectFunction {
|
||||
Fmax() { this.hasGlobalOrStdOrBslName(["fmax", "fmaxf", "fmaxl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fmin extends Function, SideEffectFunction {
|
||||
Fmin() { this.hasGlobalOrStdOrBslName(["fmin", "fminf", "fminl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fdim extends Function, SideEffectFunction {
|
||||
Fdim() { this.hasGlobalOrStdOrBslName(["fdim", "fdimf", "fdiml"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Nan extends Function, SideEffectFunction, AliasFunction {
|
||||
Nan() { this.hasGlobalOrStdOrBslName(["nan", "nanf", "nanl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = true
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* An instantiation of `std::pair<T1, T2>`.
|
||||
@@ -37,7 +39,9 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction {
|
||||
/**
|
||||
* Additional model for `std::pair` constructors.
|
||||
*/
|
||||
private class StdPairConstructor extends Constructor, TaintFunction {
|
||||
private class StdPairConstructor extends Constructor, TaintFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
{
|
||||
StdPairConstructor() { this.getDeclaringType() instanceof StdPair }
|
||||
|
||||
/**
|
||||
@@ -59,4 +63,77 @@ private class StdPairConstructor extends Constructor, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// All the constructor parameters are references with the exception of this one:
|
||||
// ```
|
||||
// template<class... Args1, class... Args2>
|
||||
// pair(std::piecewise_construct_t, std::tuple<Args1...> first_args, std::tuple<Args2...> second_args);
|
||||
// ```
|
||||
// So we need to check that the parameters are actually references
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdPairDestructor extends Destructor, AliasFunction, SideEffectFunction {
|
||||
StdPairDestructor() { this.getDeclaringType() instanceof StdPair }
|
||||
|
||||
private Type getFirstType() { result = this.getDeclaringType().getTemplateArgument(0) }
|
||||
|
||||
private Type getSecondType() { result = this.getDeclaringType().getTemplateArgument(0) }
|
||||
|
||||
private Type getAType() { result = [this.getFirstType(), this.getSecondType()] }
|
||||
|
||||
/**
|
||||
* Gets the destructor associated with the base type of this pair
|
||||
*/
|
||||
private Destructor getADestructor() { result.getDeclaringType() = this.getAType() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() {
|
||||
this.getADestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't have
|
||||
// any strange read side effects.
|
||||
not exists(this.getADestructor())
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
this.getADestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't have
|
||||
// any strange write side effects.
|
||||
not exists(this.getADestructor())
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getADestructor().(AliasFunction).parameterNeverEscapes(index)
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't cause
|
||||
// anything to escape.
|
||||
not exists(this.getADestructor()) and
|
||||
index = -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* The `std::basic_string` template class instantiations.
|
||||
@@ -78,7 +80,9 @@ abstract private class StdStringTaintFunction extends TaintFunction {
|
||||
* std::string b(a.begin(), a.end());
|
||||
* ```
|
||||
*/
|
||||
private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
||||
private class StdStringConstructor extends Constructor, StdStringTaintFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -94,6 +98,42 @@ private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdStringDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdStringDestructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +204,7 @@ private class StdStringFrontBack extends StdStringTaintFunction {
|
||||
/**
|
||||
* The (non-member) `std::string` function `operator+`.
|
||||
*/
|
||||
private class StdStringPlus extends StdStringTaintFunction {
|
||||
private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringPlus() {
|
||||
this.hasQualifiedName(["std", "bsl"], "operator+") and
|
||||
this.getUnspecifiedType() instanceof StdBasicString
|
||||
@@ -178,6 +218,22 @@ private class StdStringPlus extends StdStringTaintFunction {
|
||||
) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
or
|
||||
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +241,7 @@ private class StdStringPlus extends StdStringTaintFunction {
|
||||
* All of these functions combine the existing string with a new
|
||||
* string (or character) from one of the arguments.
|
||||
*/
|
||||
private class StdStringAppend extends StdStringTaintFunction {
|
||||
private class StdStringAppend extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringAppend() {
|
||||
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
|
||||
}
|
||||
@@ -210,6 +266,22 @@ private class StdStringAppend extends StdStringTaintFunction {
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and mustWrite = false and buffer = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [-1, 0] and buffer = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +373,7 @@ private class StdStringSubstr extends StdStringTaintFunction {
|
||||
/**
|
||||
* The `std::string` functions `at` and `operator[]`.
|
||||
*/
|
||||
private class StdStringAt extends StdStringTaintFunction {
|
||||
private class StdStringAt extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -315,6 +387,22 @@ private class StdStringAt extends StdStringTaintFunction {
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,6 +412,54 @@ private class StdBasicIStream extends ClassTemplateInstantiation {
|
||||
StdBasicIStream() { this.hasQualifiedName(["std", "bsl"], "basic_istream") }
|
||||
}
|
||||
|
||||
private class StdBasicIfStream extends ClassTemplateInstantiation {
|
||||
StdBasicIfStream() { this.hasQualifiedName(["std", "bsl"], "basic_ifstream") }
|
||||
}
|
||||
|
||||
class StdBasicIfStreamConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdBasicIfStreamConstructor() { this.getDeclaringType() instanceof StdBasicIfStream }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
exists(Type t | t = this.getParameter(i).getUnspecifiedType() |
|
||||
t instanceof PointerType and buffer = true
|
||||
or
|
||||
t instanceof ReferenceType and buffer = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class StdBasicIfStreamDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdBasicIfStreamDestructor() { this.getDeclaringType() instanceof StdBasicIfStream }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::istream` function `operator>>` (defined as a member function).
|
||||
*/
|
||||
@@ -542,6 +678,33 @@ private class StdBasicOStream extends ClassTemplateInstantiation {
|
||||
StdBasicOStream() { this.hasQualifiedName(["std", "bsl"], "basic_ostream") }
|
||||
}
|
||||
|
||||
private class StdStringLessThan extends Function, AliasFunction, SideEffectFunction {
|
||||
StdStringLessThan() {
|
||||
this.hasQualifiedName(["std", "bsl"], "operator<") and
|
||||
this.getNumberOfParameters() = 2 and
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
|
||||
StdBasicString and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
|
||||
StdBasicString
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::ostream` functions `operator<<` (defined as a member function),
|
||||
* `put` and `write`.
|
||||
|
||||
@@ -485,10 +485,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. */
|
||||
@@ -1358,6 +1365,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 +1385,13 @@ expr_allocator(
|
||||
);
|
||||
|
||||
/*
|
||||
Binary encoding of the deallocator form.
|
||||
|
||||
case @deallocator.form of
|
||||
0 = plain
|
||||
| 1 = size
|
||||
| 2 = alignment
|
||||
| 3 = size_and_alignment
|
||||
| 4 = destroying_delete
|
||||
;
|
||||
*/
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support destroying deletes
|
||||
compatibility: partial
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Support using-enum declarations.
|
||||
compatibility: partial
|
||||
usings.rel: run usings.qlo
|
||||
@@ -0,0 +1,17 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element target, Location loc, int kind
|
||||
where
|
||||
usings(u, target, loc) and
|
||||
if target instanceof @namespace then kind = 2 else kind = 1
|
||||
select u, target, loc, kind
|
||||
@@ -1,3 +1,14 @@
|
||||
## 1.1.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of `cpp/iterator-to-expired-container` ("Iterator to expired container") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
* The precision of `cpp/unsafe-strncat` ("Potentially unsafe call to strncat") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") query now produces fewer false positives.
|
||||
|
||||
## 1.0.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -38,11 +38,18 @@ private string getEofValue() {
|
||||
private predicate checkedForEof(ScanfFunctionCall call) {
|
||||
exists(IRGuardCondition gc |
|
||||
exists(Instruction i | i.getUnconvertedResultExpression() = call |
|
||||
// call == EOF
|
||||
gc.comparesEq(valueNumber(i).getAUse(), getEofValue().toInt(), _, _)
|
||||
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||
// call == EOF
|
||||
val = getEofValue().toInt()
|
||||
or
|
||||
// call == [any positive number]
|
||||
val > 0
|
||||
)
|
||||
or
|
||||
// call < 0 (EOF is guaranteed to be negative)
|
||||
gc.comparesLt(valueNumber(i).getAUse(), 0, true, _)
|
||||
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||
val >= 0
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.models.Models
|
||||
import semmle.code.cpp.commons.Buffer
|
||||
|
||||
predicate baseType(AllocationExpr alloc, Type base) {
|
||||
exists(PointerType pointer |
|
||||
@@ -30,7 +31,8 @@ predicate baseType(AllocationExpr alloc, Type base) {
|
||||
}
|
||||
|
||||
predicate decideOnSize(Type t, int size) {
|
||||
// If the codebase has more than one type with the same name, it can have more than one size.
|
||||
// If the codebase has more than one type with the same name, it can have more than one size. For
|
||||
// most purposes in this query, we use the smallest.
|
||||
size = min(t.getSize())
|
||||
}
|
||||
|
||||
@@ -45,7 +47,8 @@ where
|
||||
size = 0 or
|
||||
(allocated / size) * size = allocated
|
||||
) and
|
||||
not basesize > allocated // covered by SizeCheck.ql
|
||||
not basesize > allocated and // covered by SizeCheck.ql
|
||||
not memberMayBeVarSize(base.getUnspecifiedType(), _) // exclude variable size types
|
||||
select alloc,
|
||||
"Allocated memory (" + allocated.toString() + " bytes) is not a multiple of the size of '" +
|
||||
base.getName() + "' (" + basesize.toString() + " bytes)."
|
||||
|
||||
@@ -10,11 +10,12 @@ contains sensitive data that could somehow be retrieved by an attacker.</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Use alternative platform-supplied functions that will not get optimized away. Examples of such
|
||||
functions include <code>memset_s</code>, <code>SecureZeroMemory</code>, and <code>bzero_explicit</code>.
|
||||
Alternatively, passing the <code>-fno-builtin-memset</code> option to the GCC/Clang compiler usually
|
||||
also prevents the optimization. Finally, you can use the public-domain <code>secure_memzero</code> function
|
||||
(see references below). This function, however, is not guaranteed to work on all platforms and compilers.</p>
|
||||
<p>Use <code>memset_s</code> (from C11) instead of <code>memset</code>, as <code>memset_s</code> will not
|
||||
get optimized away. Alternatively use platform-supplied functions such as <code>SecureZeroMemory</code> or
|
||||
<code>bzero_explicit</code> that make the same guarantee. Passing the <code>-fno-builtin-memset</code>
|
||||
option to the GCC/Clang compiler usually also prevents the optimization. Finally, you can use the
|
||||
public-domain <code>secure_memzero</code> function (see references below). This function, however, is not
|
||||
guaranteed to work on all platforms and compilers.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @id cpp/unsigned-difference-expression-compared-zero
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.8
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @tags security
|
||||
* correctness
|
||||
* external/cwe/cwe-191
|
||||
|
||||
@@ -1,12 +1,31 @@
|
||||
void writeCredentials() {
|
||||
char *password = "cleartext password";
|
||||
FILE* file = fopen("credentials.txt", "w");
|
||||
|
||||
#include <sodium.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void writeCredentialsBad(FILE *file, const char *cleartextCredentials) {
|
||||
// BAD: write password to disk in cleartext
|
||||
fputs(password, file);
|
||||
|
||||
// GOOD: encrypt password first
|
||||
char *encrypted = encrypt(password);
|
||||
fputs(encrypted, file);
|
||||
fputs(cleartextCredentials, file);
|
||||
}
|
||||
|
||||
int writeCredentialsGood(FILE *file, const char *cleartextCredentials, const unsigned char *key, const unsigned char *nonce) {
|
||||
size_t credentialsLen = strlen(cleartextCredentials);
|
||||
size_t ciphertext_len = crypto_secretbox_MACBYTES + credentialsLen;
|
||||
unsigned char *ciphertext = malloc(ciphertext_len);
|
||||
if (!ciphertext) {
|
||||
logError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// encrypt the password first
|
||||
if (crypto_secretbox_easy(ciphertext, (const unsigned char *)cleartextCredentials, credentialsLen, nonce, key) != 0) {
|
||||
free(ciphertext);
|
||||
logError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// GOOD: write encrypted password to disk
|
||||
fwrite(ciphertext, 1, ciphertext_len, file);
|
||||
|
||||
free(ciphertext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,15 +19,20 @@ cleartext.</p>
|
||||
<example>
|
||||
|
||||
<p>The following example shows two ways of storing user credentials in a file. In the 'BAD' case,
|
||||
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
|
||||
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
|
||||
storing them.</p>
|
||||
|
||||
<sample src="CleartextStorage.c" />
|
||||
|
||||
<p>Note that for the 'GOOD' example to work we need to link against an encryption library (in this case libsodium),
|
||||
initialize it with a call to <code>sodium_init</code>, and create the key and nonce with
|
||||
<code>crypto_secretbox_keygen</code> and <code>randombytes_buf</code> respectively. We also need to store those
|
||||
details securely so they can be used for decryption.</p>
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
void bad(void) {
|
||||
char *password = "cleartext password";
|
||||
const char *password = "cleartext password";
|
||||
sqlite3 *credentialsDB;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
@@ -16,14 +16,15 @@ void bad(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void good(void) {
|
||||
char *password = "cleartext password";
|
||||
void good(const char *secretKey) {
|
||||
const char *password = "cleartext password";
|
||||
sqlite3 *credentialsDB;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) {
|
||||
// GOOD: database encryption enabled:
|
||||
sqlite3_exec(credentialsDB, "PRAGMA key = 'secretKey!'", NULL, NULL, NULL);
|
||||
std::string setKeyString = std::string("PRAGMA key = '") + secretKey + "'";
|
||||
sqlite3_exec(credentialsDB, setKeyString.c_str(), NULL, NULL, NULL);
|
||||
sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL);
|
||||
if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);
|
||||
@@ -33,4 +34,3 @@ void good(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,12 @@ In the 'GOOD' case, the database (and thus the credentials) are encrypted.</p>
|
||||
|
||||
<sample src="CleartextSqliteDatabase.c" />
|
||||
|
||||
<p>Note that for the 'GOOD' example to work we need to provide a secret key. Secure key generation and storage is required.</p>
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
|
||||
|
||||
|
||||
@@ -232,6 +232,7 @@ predicate nullCheckInThrowingNew(NewOrNewArrayExpr newExpr, GuardCondition guard
|
||||
from NewOrNewArrayExpr newExpr, Element element, string msg, string elementString
|
||||
where
|
||||
not newExpr.isFromUninstantiatedTemplate(_) and
|
||||
not newExpr.isFromTemplateInstantiation(_) and
|
||||
(
|
||||
noThrowInTryBlock(newExpr, element) and
|
||||
msg = "This allocation cannot throw. $@ is unnecessary." and
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The precision of `cpp/unsafe-strncat` ("Potentially unsafe call to strncat") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The precision of `cpp/iterator-to-expired-container` ("Iterator to expired container") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The precision of `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") query now produces fewer false positives.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/suspicious-allocation-size` ("Not enough memory allocated for array of pointer type") query no longer produces false positives on "variable size" `struct`s.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
|
||||
10
cpp/ql/src/change-notes/released/1.1.0.md
Normal file
10
cpp/ql/src/change-notes/released/1.1.0.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## 1.1.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of `cpp/iterator-to-expired-container` ("Iterator to expired container") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
* The precision of `cpp/unsafe-strncat` ("Potentially unsafe call to strncat") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") query now produces fewer false positives.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.3
|
||||
lastReleaseVersion: 1.1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.0.4-dev
|
||||
version: 1.1.1-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// semmle-extractor-options: -std=c++17
|
||||
// semmle-extractor-options: -std=c++20
|
||||
typedef unsigned long size_t;
|
||||
namespace std {
|
||||
enum class align_val_t : size_t {};
|
||||
|
||||
struct destroying_delete_t {
|
||||
explicit destroying_delete_t() = default;
|
||||
};
|
||||
inline constexpr destroying_delete_t destroying_delete{};
|
||||
}
|
||||
|
||||
void* operator new(size_t, float);
|
||||
@@ -37,6 +42,11 @@ struct SizedDealloc {
|
||||
void operator delete[](void*, size_t);
|
||||
};
|
||||
|
||||
struct DestroyingDealloc {
|
||||
void* operator new(size_t);
|
||||
void operator delete(DestroyingDealloc*, std::destroying_delete_t);
|
||||
};
|
||||
|
||||
struct alignas(128) Overaligned {
|
||||
char a[256];
|
||||
};
|
||||
@@ -59,6 +69,7 @@ void OperatorDelete() {
|
||||
delete static_cast<int*>(nullptr); // No destructor
|
||||
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
||||
delete static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
|
||||
delete static_cast<DestroyingDealloc*>(nullptr); // No destructor, with destroying delete.
|
||||
delete static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
|
||||
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
||||
delete static_cast<const String*>(nullptr); // Pointer to const
|
||||
@@ -103,11 +114,20 @@ struct alignas(128) FailedInitOveraligned {
|
||||
void operator delete[](void*, std::align_val_t, float); // Aligned placement
|
||||
};
|
||||
|
||||
struct alignas(128) FailedInitDestroyingDelete {
|
||||
FailedInitDestroyingDelete();
|
||||
~FailedInitDestroyingDelete();
|
||||
|
||||
void* operator new(size_t); // Non-placement
|
||||
void operator delete(FailedInitDestroyingDelete*, std::destroying_delete_t); // Destroying delete
|
||||
};
|
||||
|
||||
void TestFailedInit(int n) {
|
||||
new FailedInit();
|
||||
new FailedInit[n];
|
||||
new(1.0f) FailedInitOveraligned();
|
||||
new(1.0f) FailedInitOveraligned[10];
|
||||
new FailedInitDestroyingDelete();
|
||||
}
|
||||
|
||||
// --- non-allocating placement new ---
|
||||
|
||||
@@ -1,118 +1,123 @@
|
||||
newExprs
|
||||
| allocators.cpp:49:3:49:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:50:3:50:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
|
||||
| allocators.cpp:51:3:51:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:52:3:52:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
|
||||
| allocators.cpp:53:3:53:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
|
||||
| allocators.cpp:54:3:54:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:55:3:55:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
|
||||
| allocators.cpp:129:3:129:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
|
||||
| allocators.cpp:135:3:135:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
|
||||
| allocators.cpp:59:3:59:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:60:3:60:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
|
||||
| allocators.cpp:61:3:61:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:62:3:62:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
|
||||
| allocators.cpp:63:3:63:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
|
||||
| allocators.cpp:64:3:64:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:65:3:65:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:126:3:126:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
|
||||
| allocators.cpp:128:3:128:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
|
||||
| allocators.cpp:130:3:130:34 | new | FailedInitDestroyingDelete | void* FailedInitDestroyingDelete::operator new(size_t) | 128 | 128 | | |
|
||||
| allocators.cpp:149:3:149:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
|
||||
| allocators.cpp:155:3:155:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
|
||||
newArrayExprs
|
||||
| allocators.cpp:68:3:68:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
|
||||
| allocators.cpp:69:3:69:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
|
||||
| allocators.cpp:70:3:70:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
|
||||
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
|
||||
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
|
||||
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
|
||||
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
|
||||
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
|
||||
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
|
||||
| allocators.cpp:79:3:79:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
|
||||
| allocators.cpp:80:3:80:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
|
||||
| allocators.cpp:81:3:81:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
|
||||
| allocators.cpp:82:3:82:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
|
||||
| allocators.cpp:83:3:83:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
|
||||
| allocators.cpp:127:3:127:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
|
||||
| allocators.cpp:129:3:129:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
|
||||
| allocators.cpp:152:3:152:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
|
||||
| allocators.cpp:156:3:156:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
|
||||
| allocators.cpp:162:13:162:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
|
||||
| allocators.cpp:163:13:163:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
|
||||
| allocators.cpp:164:13:164:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
|
||||
newExprDeallocators
|
||||
| allocators.cpp:52:3:52:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:53:3:53:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
| allocators.cpp:62:3:62:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:63:3:63:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
|
||||
| allocators.cpp:126:3:126:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:128:3:128:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
| allocators.cpp:130:3:130:34 | new | FailedInitDestroyingDelete | void FailedInitDestroyingDelete::operator delete(FailedInitDestroyingDelete*, std::destroying_delete_t) | 128 | 128 | destroying |
|
||||
newArrayExprDeallocators
|
||||
| allocators.cpp:70:3:70:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
| allocators.cpp:81:3:81:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:83:3:83:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:127:3:127:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:129:3:129:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
deleteExprs
|
||||
| allocators.cpp:59:3:59:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized | false |
|
||||
| allocators.cpp:60:3:60:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized | true |
|
||||
| allocators.cpp:62:3:62:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned | false |
|
||||
| allocators.cpp:64:3:64:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
| allocators.cpp:69:3:69:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized | false |
|
||||
| allocators.cpp:70:3:70:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
| allocators.cpp:71:3:71:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized | true |
|
||||
| allocators.cpp:72:3:72:49 | delete | DestroyingDealloc | void DestroyingDealloc::operator delete(DestroyingDealloc*, std::destroying_delete_t) | 1 | 1 | destroying | true |
|
||||
| allocators.cpp:73:3:73:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned | false |
|
||||
| allocators.cpp:75:3:75:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized | false |
|
||||
deleteArrayExprs
|
||||
| allocators.cpp:78:3:78:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:79:3:79:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
|
||||
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:83:3:83:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:89:3:89:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:90:3:90:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:91:3:91:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
|
||||
| allocators.cpp:92:3:92:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:93:3:93:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:94:3:94:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
allocationFunctions
|
||||
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:9:7:9:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:10:7:10:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:121:7:121:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:122:7:122:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:123:7:123:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:124:7:124:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:153:7:153:12 | malloc | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:12:7:12:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:13:7:13:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:14:7:14:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:15:7:15:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:141:7:141:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:142:7:142:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
|
||||
| allocators.cpp:143:7:143:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:144:7:144:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:173:7:173:12 | malloc | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
allocationExprs
|
||||
| allocators.cpp:49:3:49:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:50:3:50:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:51:3:51:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:52:3:52:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:53:3:53:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:54:3:54:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:55:3:55:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:68:3:68:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:69:3:69:18 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:70:3:70:15 | new[] | getAllocatedElementType = String, getSizeExpr = n, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:71:3:71:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc |
|
||||
| allocators.cpp:72:3:72:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
|
||||
| allocators.cpp:107:3:107:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
|
||||
| allocators.cpp:108:3:108:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:109:3:109:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
|
||||
| allocators.cpp:110:3:110:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
|
||||
| allocators.cpp:129:3:129:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:132:3:132:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:135:3:135:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:136:3:136:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:142:13:142:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
|
||||
| allocators.cpp:143:13:143:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
|
||||
| allocators.cpp:144:13:144:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
|
||||
| allocators.cpp:149:8:149:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:157:50:157:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:158:26:158:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:159:31:159:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:160:16:160:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:161:34:161:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:162:23:162:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:163:3:163:8 | call to malloc | getSizeBytes = 32, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:59:3:59:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:60:3:60:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:61:3:61:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:62:3:62:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:63:3:63:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:64:3:64:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:65:3:65:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc |
|
||||
| allocators.cpp:79:3:79:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:80:3:80:18 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:81:3:81:15 | new[] | getAllocatedElementType = String, getSizeExpr = n, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:82:3:82:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc |
|
||||
| allocators.cpp:83:3:83:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc |
|
||||
| allocators.cpp:126:3:126:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc |
|
||||
| allocators.cpp:127:3:127:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:128:3:128:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc |
|
||||
| allocators.cpp:129:3:129:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc |
|
||||
| allocators.cpp:130:3:130:34 | new | getAllocatedElementType = FailedInitDestroyingDelete, getSizeBytes = 128, requiresDealloc |
|
||||
| allocators.cpp:149:3:149:21 | new | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:152:3:152:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 |
|
||||
| allocators.cpp:155:3:155:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc |
|
||||
| allocators.cpp:156:3:156:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc |
|
||||
| allocators.cpp:162:13:162:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc |
|
||||
| allocators.cpp:163:13:163:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc |
|
||||
| allocators.cpp:164:13:164:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc |
|
||||
| allocators.cpp:169:8:169:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:177:50:177:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:178:26:178:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:179:31:179:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:180:16:180:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc |
|
||||
| allocators.cpp:181:34:181:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
|
||||
| allocators.cpp:182:23:182:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
|
||||
| allocators.cpp:183:3:183:8 | call to malloc | getSizeBytes = 32, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
|
||||
deallocationFunctions
|
||||
| allocators.cpp:11:6:11:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:12:6:12:22 | operator delete[] | getFreedArg = 0 |
|
||||
| allocators.cpp:13:6:13:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:14:6:14:22 | operator delete[] | getFreedArg = 0 |
|
||||
| allocators.cpp:16:6:16:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:17:6:17:22 | operator delete[] | getFreedArg = 0 |
|
||||
| allocators.cpp:18:6:18:20 | operator delete | getFreedArg = 0 |
|
||||
| allocators.cpp:19:6:19:22 | operator delete[] | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
|
||||
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
|
||||
deallocationExprs
|
||||
| allocators.cpp:59:3:59:35 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:60:3:60:38 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:61:3:61:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:62:3:62:43 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:63:3:63:47 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:64:3:64:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:78:3:78:37 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:79:3:79:40 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:80:3:80:46 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:81:3:81:45 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:82:3:82:49 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:83:3:83:23 | delete[] | getFreedExpr = call to GetPointer |
|
||||
| allocators.cpp:150:2:150:16 | call to operator delete | getFreedExpr = ptr |
|
||||
| allocators.cpp:69:3:69:35 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:70:3:70:38 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:71:3:71:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:72:3:72:49 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:73:3:73:43 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:74:3:74:47 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:75:3:75:44 | delete | getFreedExpr = 0 |
|
||||
| allocators.cpp:89:3:89:37 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:90:3:90:40 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:91:3:91:46 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:92:3:92:45 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:93:3:93:49 | delete[] | getFreedExpr = 0 |
|
||||
| allocators.cpp:94:3:94:23 | delete[] | getFreedExpr = call to GetPointer |
|
||||
| allocators.cpp:170:2:170:16 | call to operator delete | getFreedExpr = ptr |
|
||||
|
||||
@@ -50,10 +50,11 @@ query predicate newExprDeallocators(
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
alignment = allocatedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -68,10 +69,11 @@ query predicate newArrayExprDeallocators(
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -87,10 +89,11 @@ query predicate deleteExprs(
|
||||
type = deletedType.toString() and
|
||||
size = deletedType.getSize() and
|
||||
alignment = deletedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
) and
|
||||
if exists(expr.getDeallocatorCall())
|
||||
then hasDeallocatorCall = true
|
||||
@@ -108,10 +111,11 @@ query predicate deleteArrayExprs(
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
exists(string sized, string aligned, string destroying |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
(if expr.isDestroyingDeleteDeallocation() then destroying = "destroying" else destroying = "") and
|
||||
form = sized + " " + aligned + " " + destroying
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ missingOperand
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
| ir.cpp:2670:3:2670:9 | Phi: call to use_int | Instruction 'Phi: call to use_int' is missing an operand for predecessor block 'EnterFunction: phi_with_single_input_at_merge' in function '$@'. | ir.cpp:2663:13:2663:42 | void phi_with_single_input_at_merge(bool) | void phi_with_single_input_at_merge(bool) |
|
||||
missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
|
||||
@@ -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
|
||||
|
||||
3095
cpp/ql/test/library-tests/ir/ir/many-defs-per-use.cpp
Normal file
3095
cpp/ql/test/library-tests/ir/ir/many-defs-per-use.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,4 +7,61 @@ class TestConstexpr {
|
||||
constexpr int member_const_constexpr() const { return 0; }
|
||||
};
|
||||
|
||||
struct TestExplict {
|
||||
explicit TestExplict();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct TestExplicitBool {
|
||||
explicit(sizeof(T) == 1)
|
||||
TestExplicitBool(const T);
|
||||
};
|
||||
|
||||
explicit TestExplicitBool(const double) -> TestExplicitBool<int>;
|
||||
|
||||
template<typename T>
|
||||
explicit(sizeof(T) == 4)
|
||||
TestExplicitBool(const T) -> TestExplicitBool<int>;
|
||||
|
||||
void TestExplicitBoolFun() {
|
||||
new TestExplicitBool<char>(0);
|
||||
new TestExplicitBool<int>(0);
|
||||
new TestExplicitBool(0.0f);
|
||||
new TestExplicitBool(0.0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct TestExplicitBool2 {
|
||||
explicit(sizeof(T) == 1)
|
||||
TestExplicitBool2(const T);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
TestExplicitBool2<T>::TestExplicitBool2(const T) { }
|
||||
|
||||
void TestExplicitBoolFun2() {
|
||||
new TestExplicitBool2<char>(0);
|
||||
new TestExplicitBool2<int>(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct TestExplicitBool3 {
|
||||
template<typename U>
|
||||
explicit(sizeof(T) == 1)
|
||||
TestExplicitBool3(const T, const U);
|
||||
};
|
||||
|
||||
template<typename T> template<typename U>
|
||||
TestExplicitBool3<T>::TestExplicitBool3(const T, const U) { }
|
||||
|
||||
void TestExplicitBoolFun3() {
|
||||
new TestExplicitBool3<char>(0, 0);
|
||||
new TestExplicitBool3<int>(0, 0);
|
||||
}
|
||||
|
||||
struct TestExplicitBool4 {
|
||||
explicit(sizeof(char) == 1)
|
||||
TestExplicitBool4(const char);
|
||||
};
|
||||
|
||||
} // namespace cpp20
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
| cpp20.cpp:15:8:15:23 | TestExplicitBool<char> | file://:0:0:0:0 | char | cpp20.cpp:17:5:17:20 | TestExplicitBool | explicit, extern, public |
|
||||
| cpp20.cpp:15:8:15:23 | TestExplicitBool<int> | file://:0:0:0:0 | int | cpp20.cpp:17:5:17:20 | TestExplicitBool | extern, public |
|
||||
| cpp20.cpp:34:8:34:24 | TestExplicitBool2<char> | file://:0:0:0:0 | char | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | explicit, public |
|
||||
| cpp20.cpp:34:8:34:24 | TestExplicitBool2<int> | file://:0:0:0:0 | int | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | public |
|
||||
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<char> | file://:0:0:0:0 | char | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | explicit, public |
|
||||
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<char> | file://:0:0:0:0 | char | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | explicit, extern, public |
|
||||
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<int> | file://:0:0:0:0 | int | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | public |
|
||||
| cpp20.cpp:48:8:48:24 | TestExplicitBool3<int> | file://:0:0:0:0 | int | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | extern, public |
|
||||
@@ -0,0 +1,7 @@
|
||||
import cpp
|
||||
|
||||
from MemberFunction m, ClassTemplateInstantiation c, string specifiers
|
||||
where
|
||||
c.getAMember() = m and
|
||||
specifiers = concat(string s | s = m.getASpecifier().getName() | s, ", ")
|
||||
select c, c.getATemplateArgument(), m, specifiers
|
||||
@@ -1,146 +1,80 @@
|
||||
| Class | specifiers2pp.cpp:8:7:8:13 | MyClass | MyClass | abstract |
|
||||
| Class | specifiers2pp.cpp:24:7:24:14 | MyClass2 | MyClass2 | abstract |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| Function | specifiers2.c:11:6:11:6 | f | f | c_linkage |
|
||||
| Function | specifiers2.c:11:6:11:6 | f | f | extern |
|
||||
| Function | specifiers2.c:12:13:12:13 | f | f | c_linkage |
|
||||
| Function | specifiers2.c:12:13:12:13 | f | f | extern |
|
||||
| Function | specifiers2.c:13:13:13:13 | f | f | c_linkage |
|
||||
| Function | specifiers2.c:13:13:13:13 | f | f | extern |
|
||||
| Function | specifiers2.c:15:13:15:13 | g | g | c_linkage |
|
||||
| Function | specifiers2.c:15:13:15:13 | g | g | extern |
|
||||
| Function | specifiers2.c:16:13:16:13 | g | g | c_linkage |
|
||||
| Function | specifiers2.c:16:13:16:13 | g | g | extern |
|
||||
| Function | specifiers2.c:21:6:21:12 | somefun | somefun | c_linkage |
|
||||
| Function | specifiers2.c:21:6:21:12 | somefun | somefun | extern |
|
||||
| Function | specifiers2.c:25:12:25:14 | add | add | c_linkage |
|
||||
| Function | specifiers2.c:25:12:25:14 | add | add | inline |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | inline |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | inline |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | public |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | public |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | explicit |
|
||||
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | extern |
|
||||
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | public |
|
||||
| Function | specifiers2pp.cpp:12:14:12:22 | publicFun | publicFun | inline |
|
||||
| Function | specifiers2pp.cpp:12:14:12:22 | publicFun | publicFun | public |
|
||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | declared_virtual |
|
||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | extern |
|
||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | public |
|
||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | pure |
|
||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | virtual |
|
||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | declared_virtual |
|
||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | extern |
|
||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | public |
|
||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | virtual |
|
||||
| Function | specifiers2pp.cpp:18:14:18:23 | privateFun | privateFun | inline |
|
||||
| Function | specifiers2pp.cpp:18:14:18:23 | privateFun | privateFun | private |
|
||||
| Function | specifiers2pp.cpp:21:14:21:25 | protectedFun | protectedFun | inline |
|
||||
| Function | specifiers2pp.cpp:21:14:21:25 | protectedFun | protectedFun | protected |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | inline |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | inline |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | inline |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | declared_virtual |
|
||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | extern |
|
||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | override |
|
||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | public |
|
||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | virtual |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr, inline, is_constexpr, private |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const, declared_constexpr, inline, is_constexpr, private |
|
||||
| Function | cpp20.cpp:10:8:10:8 | TestExplict | TestExplict | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:10:8:10:8 | TestExplict | TestExplict | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:10:8:10:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:10:8:10:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:11:14:11:24 | TestExplict | TestExplict | explicit, extern, public |
|
||||
| Function | cpp20.cpp:17:5:17:20 | TestExplicitBool | TestExplicitBool | explicit, extern, public |
|
||||
| Function | cpp20.cpp:17:5:17:20 | TestExplicitBool | TestExplicitBool | extern, public |
|
||||
| Function | cpp20.cpp:17:5:17:20 | TestExplicitBool | TestExplicitBool | extern, public |
|
||||
| Function | cpp20.cpp:24:1:24:16 | TestExplicitBool | TestExplicitBool | has_trailing_return_type |
|
||||
| Function | cpp20.cpp:40:1:40:39 | TestExplicitBool2 | TestExplicitBool2 | public |
|
||||
| Function | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | TestExplicitBool2 | explicit, public |
|
||||
| Function | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | TestExplicitBool2 | public |
|
||||
| Function | cpp20.cpp:40:23:40:23 | TestExplicitBool2 | TestExplicitBool2 | public |
|
||||
| Function | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | TestExplicitBool3 | explicit, public |
|
||||
| Function | cpp20.cpp:51:5:51:5 | TestExplicitBool3 | TestExplicitBool3 | public |
|
||||
| Function | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | TestExplicitBool3 | explicit, extern, public |
|
||||
| Function | cpp20.cpp:51:5:51:21 | TestExplicitBool3 | TestExplicitBool3 | extern, public |
|
||||
| Function | cpp20.cpp:55:1:55:39 | TestExplicitBool3 | TestExplicitBool3 | public |
|
||||
| Function | cpp20.cpp:62:8:62:8 | TestExplicitBool4 | TestExplicitBool4 | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:62:8:62:8 | TestExplicitBool4 | TestExplicitBool4 | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:62:8:62:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:62:8:62:8 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | cpp20.cpp:64:5:64:21 | TestExplicitBool4 | TestExplicitBool4 | explicit, extern, public |
|
||||
| Function | file://:0:0:0:0 | operator delete | operator delete | extern |
|
||||
| Function | file://:0:0:0:0 | operator new | operator new | extern |
|
||||
| Function | specifiers2.c:11:6:11:6 | f | f | c_linkage, extern |
|
||||
| Function | specifiers2.c:12:13:12:13 | f | f | c_linkage, extern |
|
||||
| Function | specifiers2.c:13:13:13:13 | f | f | c_linkage, extern |
|
||||
| Function | specifiers2.c:15:13:15:13 | g | g | c_linkage, extern |
|
||||
| Function | specifiers2.c:16:13:16:13 | g | g | c_linkage, extern |
|
||||
| Function | specifiers2.c:21:6:21:12 | somefun | somefun | c_linkage, extern |
|
||||
| Function | specifiers2.c:25:12:25:14 | add | add | c_linkage, inline |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | MyClass | MyClass | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern, inline, public |
|
||||
| Function | specifiers2pp.cpp:8:7:8:7 | operator= | operator= | extern, inline, public |
|
||||
| Function | specifiers2pp.cpp:10:18:10:24 | MyClass | MyClass | explicit, extern, public |
|
||||
| Function | specifiers2pp.cpp:12:14:12:22 | publicFun | publicFun | inline, public |
|
||||
| Function | specifiers2pp.cpp:13:21:13:26 | getInt | getInt | declared_virtual, extern, public, pure, virtual |
|
||||
| Function | specifiers2pp.cpp:14:21:14:21 | f | f | declared_virtual, extern, public, virtual |
|
||||
| Function | specifiers2pp.cpp:18:14:18:23 | privateFun | privateFun | inline, private |
|
||||
| Function | specifiers2pp.cpp:21:14:21:25 | protectedFun | protectedFun | inline, protected |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | MyClass2 | MyClass2 | extern, inline, public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern, inline, public |
|
||||
| Function | specifiers2pp.cpp:24:7:24:7 | operator= | operator= | extern, inline, public |
|
||||
| Function | specifiers2pp.cpp:26:21:26:21 | f | f | declared_virtual, extern, override, public, virtual |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:33:5:33:18 | fun | fun | public |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:40:12:40:18 | someFun | someFun | extern |
|
||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | c_linkage |
|
||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | extern |
|
||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | c_linkage |
|
||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | extern |
|
||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | c_linkage |
|
||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | static |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | extern |
|
||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | extern |
|
||||
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | extern |
|
||||
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | extern |
|
||||
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | void_param_list |
|
||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | c_linkage, extern |
|
||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | c_linkage, extern |
|
||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | c_linkage, static |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern, inline, is_constexpr, public |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const, declared_constexpr, inline, is_constexpr, private |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const, declared_constexpr, inline, is_constexpr, private |
|
||||
| FunctionDeclarationEntry | cpp20.cpp:11:14:11:24 | declaration of TestExplict | TestExplict | explicit |
|
||||
| FunctionDeclarationEntry | cpp20.cpp:40:23:40:23 | definition of TestExplicitBool2 | TestExplicitBool2 | explicit |
|
||||
| FunctionDeclarationEntry | cpp20.cpp:51:5:51:5 | definition of TestExplicitBool3 | TestExplicitBool3 | explicit |
|
||||
| FunctionDeclarationEntry | cpp20.cpp:51:5:51:21 | declaration of TestExplicitBool3 | TestExplicitBool3 | explicit |
|
||||
| FunctionDeclarationEntry | cpp20.cpp:64:5:64:21 | declaration of TestExplicitBool4 | TestExplicitBool4 | explicit |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage, void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage, extern, void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:13:13:13:13 | declaration of f | f | c_linkage, extern, void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:15:13:15:13 | declaration of g | g | c_linkage, extern, void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:16:13:16:13 | declaration of g | g | c_linkage, extern, void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:21:6:21:12 | declaration of somefun | somefun | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:25:12:25:14 | definition of add | add | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:2:6:2:9 | definition of afun | afun | void_param_list |
|
||||
@@ -154,28 +88,19 @@
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:31:13:31:15 | declaration of fun | fun | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:33:5:33:18 | definition of fun | fun | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:40:12:40:18 | declaration of someFun | someFun | extern |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:41:16:41:23 | declaration of someFun2 | someFun2 | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:41:16:41:23 | declaration of someFun2 | someFun2 | extern |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:43:9:43:16 | declaration of someFun3 | someFun3 | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:43:9:43:16 | declaration of someFun3 | someFun3 | extern |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:44:16:44:23 | declaration of someFun4 | someFun4 | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:44:16:44:23 | declaration of someFun4 | someFun4 | static |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:41:16:41:23 | declaration of someFun2 | someFun2 | c_linkage, extern |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:43:9:43:16 | declaration of someFun3 | someFun3 | c_linkage, extern |
|
||||
| FunctionDeclarationEntry | specifiers2pp.cpp:44:16:44:23 | declaration of someFun4 | someFun4 | c_linkage, static |
|
||||
| TypedefType | file://:0:0:0:0 | Const | Const | const |
|
||||
| TypedefType | specifiers2.c:27:19:27:26 | constInt | constInt | const |
|
||||
| TypedefType | specifiers2pp.cpp:47:20:47:32 | const_pointer | const_pointer | const |
|
||||
| TypedefType | specifiers2pp.cpp:49:32:49:53 | volatile_const_pointer | volatile_const_pointer | const |
|
||||
| TypedefType | specifiers2pp.cpp:49:32:49:53 | volatile_const_pointer | volatile_const_pointer | volatile |
|
||||
| TypedefType | specifiers2pp.cpp:50:32:50:54 | volatile_const_pointer2 | volatile_const_pointer2 | const |
|
||||
| TypedefType | specifiers2pp.cpp:50:32:50:54 | volatile_const_pointer2 | volatile_const_pointer2 | volatile |
|
||||
| TypedefType | specifiers2pp.cpp:53:23:53:45 | volatile_const_pointer3 | volatile_const_pointer3 | const |
|
||||
| TypedefType | specifiers2pp.cpp:53:23:53:45 | volatile_const_pointer3 | volatile_const_pointer3 | volatile |
|
||||
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | const |
|
||||
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | restrict |
|
||||
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | volatile |
|
||||
| TypedefType | specifiers2pp.cpp:49:32:49:53 | volatile_const_pointer | volatile_const_pointer | const, volatile |
|
||||
| TypedefType | specifiers2pp.cpp:50:32:50:54 | volatile_const_pointer2 | volatile_const_pointer2 | const, volatile |
|
||||
| TypedefType | specifiers2pp.cpp:53:23:53:45 | volatile_const_pointer3 | volatile_const_pointer3 | const, volatile |
|
||||
| TypedefType | specifiers2pp.cpp:54:44:54:74 | volatile_const_restrict_pointer | volatile_const_restrict_pointer | const, restrict, volatile |
|
||||
| TypedefType | specifiers2pp.cpp:56:28:56:32 | Const | Const | const |
|
||||
| TypedefType | specifiers2pp.cpp:58:7:58:15 | Const_int | Const_int | const |
|
||||
| TypedefType | specifiers2pp.cpp:60:28:60:45 | volatile_Const_int | volatile_Const_int | const |
|
||||
| TypedefType | specifiers2pp.cpp:60:28:60:45 | volatile_Const_int | volatile_Const_int | volatile |
|
||||
| TypedefType | specifiers2pp.cpp:60:28:60:45 | volatile_Const_int | volatile_Const_int | const, volatile |
|
||||
| Variable | specifiers2.c:8:12:8:12 | j | j | extern |
|
||||
| Variable | specifiers2.c:9:12:9:12 | j | j | extern |
|
||||
| Variable | specifiers2.c:18:21:18:23 | svi | svi | static |
|
||||
|
||||
@@ -14,16 +14,20 @@ string interesting(Element e) {
|
||||
e instanceof VariableDeclarationEntry and result = "VariableDeclarationEntry"
|
||||
}
|
||||
|
||||
from Element e, string name, string specifier
|
||||
from Element e, string name, string specifiers
|
||||
where
|
||||
(
|
||||
name = e.(Declaration).getName() or
|
||||
name = e.(DeclarationEntry).getName() or
|
||||
name = e.(Type).toString()
|
||||
) and
|
||||
(
|
||||
specifier = e.(Declaration).getASpecifier().toString() or
|
||||
specifier = e.(DeclarationEntry).getASpecifier() or
|
||||
specifier = e.(TypedefType).getBaseType().getASpecifier().toString()
|
||||
)
|
||||
select interesting(e), e, name, specifier
|
||||
specifiers =
|
||||
concat(string s |
|
||||
s = e.(Declaration).getASpecifier().toString() or
|
||||
s = e.(DeclarationEntry).getASpecifier() or
|
||||
s = e.(TypedefType).getBaseType().getASpecifier().toString()
|
||||
|
|
||||
s, ", "
|
||||
) and
|
||||
specifiers != ""
|
||||
select interesting(e), e, name, specifiers
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
| cpp20.cpp:17:28:17:28 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:17:28:17:28 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:17:28:17:28 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:24:24:24:24 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:40:47:40:47 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:40:47:40:47 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:40:47:40:47 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:29:51:29 | (unnamed parameter 0) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const U | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const U | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:51:38:51:38 | (unnamed parameter 1) | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:55:47:55:47 | (unnamed parameter 0) | file://:0:0:0:0 | const T | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:55:56:55:56 | (unnamed parameter 1) | file://:0:0:0:0 | const U | file://:0:0:0:0 | const |
|
||||
| cpp20.cpp:64:23:64:32 | (unnamed parameter 0) | file://:0:0:0:0 | const char | file://:0:0:0:0 | const |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const double | file://:0:0:0:0 | const |
|
||||
| specifiers2.c:18:21:18:23 | svi | file://:0:0:0:0 | volatile int | file://:0:0:0:0 | volatile |
|
||||
| specifiers2.c:19:11:19:12 | ci | file://:0:0:0:0 | const int | file://:0:0:0:0 | const |
|
||||
| specifiers2.c:21:34:21:34 | p | file://:0:0:0:0 | char *__restrict__ | file://:0:0:0:0 | restrict |
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| cpp20.cpp:17:5:17:20 | TestExplicitBool | extern, public |
|
||||
| cpp20.cpp:40:1:40:39 | TestExplicitBool2 | public |
|
||||
| cpp20.cpp:40:23:40:23 | TestExplicitBool2 | public |
|
||||
| cpp20.cpp:55:1:55:39 | TestExplicitBool3 | public |
|
||||
@@ -0,0 +1,7 @@
|
||||
import cpp
|
||||
|
||||
from MemberFunction m, TemplateClass c, string specifiers
|
||||
where
|
||||
c.getAMember() = m and
|
||||
specifiers = concat(string s | s = m.getASpecifier().getName() | s, ", ")
|
||||
select m, specifiers
|
||||
@@ -26,8 +26,11 @@
|
||||
| test.cpp:128:15:128:16 | v4 |
|
||||
| test.cpp:185:10:185:12 | cpy |
|
||||
| test.cpp:199:10:199:12 | cpy |
|
||||
| test.cpp:208:7:208:7 | a |
|
||||
| test.cpp:214:7:214:7 | a |
|
||||
| test.cpp:213:7:213:7 | a |
|
||||
| test.cpp:219:7:219:7 | a |
|
||||
| test.cpp:228:14:228:18 | data1 |
|
||||
| test.cpp:236:14:236:18 | data1 |
|
||||
| test.cpp:237:14:237:18 | data2 |
|
||||
| test_free.cpp:11:10:11:10 | a |
|
||||
| test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:16:10:16:10 | a |
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
edges
|
||||
| test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | provenance | |
|
||||
| test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | provenance | |
|
||||
| test.cpp:213:7:213:7 | pointer to free output argument | test.cpp:214:2:214:2 | a | provenance | |
|
||||
| test.cpp:219:7:219:7 | pointer to free output argument | test.cpp:220:2:220:2 | a | provenance | |
|
||||
| test.cpp:228:12:228:12 | *p [post update] [data1] | test.cpp:229:2:229:2 | *p [data1] | provenance | |
|
||||
| test.cpp:228:14:228:18 | pointer to operator delete[] output argument | test.cpp:228:12:228:12 | *p [post update] [data1] | provenance | |
|
||||
| test.cpp:229:2:229:2 | *p [data1] | test.cpp:229:4:229:8 | data1 | provenance | |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | provenance | |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | provenance | |
|
||||
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | provenance | |
|
||||
@@ -33,10 +36,14 @@ edges
|
||||
| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
|
||||
| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | provenance | |
|
||||
nodes
|
||||
| test.cpp:208:7:208:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:209:2:209:2 | a | semmle.label | a |
|
||||
| test.cpp:214:7:214:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:215:2:215:2 | a | semmle.label | a |
|
||||
| test.cpp:213:7:213:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:214:2:214:2 | a | semmle.label | a |
|
||||
| test.cpp:219:7:219:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:220:2:220:2 | a | semmle.label | a |
|
||||
| test.cpp:228:12:228:12 | *p [post update] [data1] | semmle.label | *p [post update] [data1] |
|
||||
| test.cpp:228:14:228:18 | pointer to operator delete[] output argument | semmle.label | pointer to operator delete[] output argument |
|
||||
| test.cpp:229:2:229:2 | *p [data1] | semmle.label | *p [data1] |
|
||||
| test.cpp:229:4:229:8 | data1 | semmle.label | data1 |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
|
||||
| test_free.cpp:13:5:13:6 | * ... | semmle.label | * ... |
|
||||
@@ -88,8 +95,9 @@ nodes
|
||||
| test_free.cpp:332:5:332:6 | * ... | semmle.label | * ... |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:209:2:209:2 | a | test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | Memory may have been previously freed by $@. | test.cpp:208:2:208:5 | call to free | call to free |
|
||||
| test.cpp:215:2:215:2 | a | test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | Memory may have been previously freed by $@. | test.cpp:214:2:214:5 | call to free | call to free |
|
||||
| test.cpp:214:2:214:2 | a | test.cpp:213:7:213:7 | pointer to free output argument | test.cpp:214:2:214:2 | a | Memory may have been previously freed by $@. | test.cpp:213:2:213:5 | call to free | call to free |
|
||||
| test.cpp:220:2:220:2 | a | test.cpp:219:7:219:7 | pointer to free output argument | test.cpp:220:2:220:2 | a | Memory may have been previously freed by $@. | test.cpp:219:2:219:5 | call to free | call to free |
|
||||
| test.cpp:229:4:229:8 | data1 | test.cpp:228:14:228:18 | pointer to operator delete[] output argument | test.cpp:229:4:229:8 | data1 | Memory may have been previously freed by $@. | test.cpp:228:2:228:18 | delete[] | delete[] |
|
||||
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:13:5:13:6 | * ... | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
|
||||
@@ -201,6 +201,11 @@ void test_strndupa_dealloc() {
|
||||
|
||||
// ---
|
||||
|
||||
struct DataPair {
|
||||
char *data1;
|
||||
char *data2;
|
||||
};
|
||||
|
||||
void test_reassignment() {
|
||||
char *a = (char *)malloc(128);
|
||||
char *b = (char *)malloc(128);
|
||||
@@ -213,4 +218,21 @@ void test_reassignment() {
|
||||
|
||||
free(a);
|
||||
a[0] = 0; // BAD
|
||||
|
||||
DataPair p;
|
||||
p.data1 = new char[128];
|
||||
p.data2 = new char[128];
|
||||
p.data1[0] = 0; // GOOD
|
||||
p.data2[0] = 0; // GOOD
|
||||
|
||||
delete [] p.data1;
|
||||
p.data1[0] = 0; // BAD
|
||||
p.data2[0] = 0; // GOOD
|
||||
|
||||
p.data1 = new char[128];
|
||||
p.data1[0] = 0; // GOOD
|
||||
p.data2[0] = 0; // GOOD
|
||||
|
||||
delete [] p.data1;
|
||||
delete [] p.data2;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,21 @@ edges
|
||||
| test.cpp:420:19:420:20 | scanf output argument | test.cpp:423:7:423:7 | i | provenance | |
|
||||
| test.cpp:455:41:455:46 | sscanf output argument | test.cpp:460:6:460:10 | value | provenance | |
|
||||
| test.cpp:467:20:467:25 | scanf output argument | test.cpp:474:6:474:10 | value | provenance | |
|
||||
| test.cpp:480:25:480:26 | scanf output argument | test.cpp:484:9:484:9 | i | provenance | |
|
||||
| test.cpp:491:25:491:26 | scanf output argument | test.cpp:495:8:495:8 | i | provenance | |
|
||||
| test.cpp:501:25:501:26 | scanf output argument | test.cpp:505:9:505:9 | i | provenance | |
|
||||
| test.cpp:512:25:512:26 | scanf output argument | test.cpp:516:9:516:9 | i | provenance | |
|
||||
| test.cpp:525:35:525:36 | sscanf output argument | test.cpp:527:8:527:8 | a | provenance | |
|
||||
| test.cpp:525:35:525:36 | sscanf output argument | test.cpp:531:8:531:8 | a | provenance | |
|
||||
| test.cpp:525:39:525:40 | sscanf output argument | test.cpp:528:8:528:8 | b | provenance | |
|
||||
| test.cpp:525:39:525:40 | sscanf output argument | test.cpp:532:8:532:8 | b | provenance | |
|
||||
| test.cpp:525:43:525:44 | sscanf output argument | test.cpp:533:8:533:8 | c | provenance | |
|
||||
| test.cpp:541:35:541:36 | sscanf output argument | test.cpp:543:8:543:8 | d | provenance | |
|
||||
| test.cpp:541:35:541:36 | sscanf output argument | test.cpp:548:8:548:8 | d | provenance | |
|
||||
| test.cpp:541:39:541:40 | sscanf output argument | test.cpp:544:8:544:8 | e | provenance | |
|
||||
| test.cpp:541:39:541:40 | sscanf output argument | test.cpp:549:8:549:8 | e | provenance | |
|
||||
| test.cpp:541:43:541:44 | sscanf output argument | test.cpp:545:8:545:8 | f | provenance | |
|
||||
| test.cpp:541:43:541:44 | sscanf output argument | test.cpp:550:8:550:8 | f | provenance | |
|
||||
nodes
|
||||
| test.cpp:34:15:34:16 | scanf output argument | semmle.label | scanf output argument |
|
||||
| test.cpp:35:7:35:7 | i | semmle.label | i |
|
||||
@@ -114,6 +129,31 @@ nodes
|
||||
| test.cpp:460:6:460:10 | value | semmle.label | value |
|
||||
| test.cpp:467:20:467:25 | scanf output argument | semmle.label | scanf output argument |
|
||||
| test.cpp:474:6:474:10 | value | semmle.label | value |
|
||||
| test.cpp:480:25:480:26 | scanf output argument | semmle.label | scanf output argument |
|
||||
| test.cpp:484:9:484:9 | i | semmle.label | i |
|
||||
| test.cpp:491:25:491:26 | scanf output argument | semmle.label | scanf output argument |
|
||||
| test.cpp:495:8:495:8 | i | semmle.label | i |
|
||||
| test.cpp:501:25:501:26 | scanf output argument | semmle.label | scanf output argument |
|
||||
| test.cpp:505:9:505:9 | i | semmle.label | i |
|
||||
| test.cpp:512:25:512:26 | scanf output argument | semmle.label | scanf output argument |
|
||||
| test.cpp:516:9:516:9 | i | semmle.label | i |
|
||||
| test.cpp:525:35:525:36 | sscanf output argument | semmle.label | sscanf output argument |
|
||||
| test.cpp:525:39:525:40 | sscanf output argument | semmle.label | sscanf output argument |
|
||||
| test.cpp:525:43:525:44 | sscanf output argument | semmle.label | sscanf output argument |
|
||||
| test.cpp:527:8:527:8 | a | semmle.label | a |
|
||||
| test.cpp:528:8:528:8 | b | semmle.label | b |
|
||||
| test.cpp:531:8:531:8 | a | semmle.label | a |
|
||||
| test.cpp:532:8:532:8 | b | semmle.label | b |
|
||||
| test.cpp:533:8:533:8 | c | semmle.label | c |
|
||||
| test.cpp:541:35:541:36 | sscanf output argument | semmle.label | sscanf output argument |
|
||||
| test.cpp:541:39:541:40 | sscanf output argument | semmle.label | sscanf output argument |
|
||||
| test.cpp:541:43:541:44 | sscanf output argument | semmle.label | sscanf output argument |
|
||||
| test.cpp:543:8:543:8 | d | semmle.label | d |
|
||||
| test.cpp:544:8:544:8 | e | semmle.label | e |
|
||||
| test.cpp:545:8:545:8 | f | semmle.label | f |
|
||||
| test.cpp:548:8:548:8 | d | semmle.label | d |
|
||||
| test.cpp:549:8:549:8 | e | semmle.label | e |
|
||||
| test.cpp:550:8:550:8 | f | semmle.label | f |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:35:7:35:7 | i | test.cpp:34:15:34:16 | scanf output argument | test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
|
||||
@@ -134,3 +174,6 @@ subpaths
|
||||
| test.cpp:423:7:423:7 | i | test.cpp:420:19:420:20 | scanf output argument | test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
|
||||
| test.cpp:460:6:460:10 | value | test.cpp:455:41:455:46 | sscanf output argument | test.cpp:460:6:460:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:455:12:455:17 | call to sscanf | call to sscanf |
|
||||
| test.cpp:474:6:474:10 | value | test.cpp:467:20:467:25 | scanf output argument | test.cpp:474:6:474:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:467:8:467:12 | call to scanf | call to scanf |
|
||||
| test.cpp:484:9:484:9 | i | test.cpp:480:25:480:26 | scanf output argument | test.cpp:484:9:484:9 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:480:13:480:17 | call to scanf | call to scanf |
|
||||
| test.cpp:495:8:495:8 | i | test.cpp:491:25:491:26 | scanf output argument | test.cpp:495:8:495:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:491:13:491:17 | call to scanf | call to scanf |
|
||||
| test.cpp:545:8:545:8 | f | test.cpp:541:43:541:44 | sscanf output argument | test.cpp:545:8:545:8 | f | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 3. | test.cpp:541:10:541:15 | call to sscanf | call to sscanf |
|
||||
|
||||
@@ -472,4 +472,84 @@ void check_for_negative_test() {
|
||||
return;
|
||||
}
|
||||
use(value);
|
||||
}
|
||||
}
|
||||
|
||||
void multiple_checks() {
|
||||
{
|
||||
int i;
|
||||
int res = scanf("%d", &i);
|
||||
|
||||
if (res >= 0) {
|
||||
if (res != 0) {
|
||||
use(i); // GOOD: checks return value [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
int res = scanf("%d", &i);
|
||||
|
||||
if (res < 0) return;
|
||||
if (res != 0) {
|
||||
use(i); // GOOD: checks return value [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
int res = scanf("%d", &i);
|
||||
|
||||
if (res >= 1) {
|
||||
if (res != 0) {
|
||||
use(i); // GOOD: checks return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
int res = scanf("%d", &i);
|
||||
|
||||
if (res == 1) {
|
||||
if (res != 0) {
|
||||
use(i); // GOOD: checks return value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void switch_cases(const char *data) {
|
||||
float a, b, c;
|
||||
|
||||
switch (sscanf(data, "%f %f %f", &a, &b, &c)) {
|
||||
case 2:
|
||||
use(a); // GOOD
|
||||
use(b); // GOOD
|
||||
break;
|
||||
case 3:
|
||||
use(a); // GOOD
|
||||
use(b); // GOOD
|
||||
use(c); // GOOD
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
float d, e, f;
|
||||
|
||||
switch (sscanf(data, "%f %f %f", &d, &e, &f)) {
|
||||
case 2:
|
||||
use(d); // GOOD
|
||||
use(e); // GOOD
|
||||
use(f); // BAD
|
||||
break;
|
||||
case 3:
|
||||
use(d); // GOOD
|
||||
use(e); // GOOD
|
||||
use(f); // GOOD
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
| test2.c:17:20:17:25 | call to malloc | Allocated memory (33 bytes) is not a multiple of the size of 'double' (8 bytes). |
|
||||
| test2.c:32:23:32:28 | call to malloc | Allocated memory (28 bytes) is not a multiple of the size of 'long long' (8 bytes). |
|
||||
| test2.c:33:20:33:25 | call to malloc | Allocated memory (20 bytes) is not a multiple of the size of 'double' (8 bytes). |
|
||||
| test2.c:85:24:85:29 | call to malloc | Allocated memory (1159 bytes) is not a multiple of the size of 'MyFixedStruct' (1032 bytes). |
|
||||
|
||||
@@ -60,7 +60,7 @@ void test_union() {
|
||||
}
|
||||
|
||||
// --- custom allocators ---
|
||||
|
||||
|
||||
void *MyMalloc1(size_t size) { return malloc(size); }
|
||||
void *MyMalloc2(size_t size);
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ void good1(void) {
|
||||
}
|
||||
|
||||
// --- custom allocators ---
|
||||
|
||||
|
||||
void *MyMalloc1(size_t size) { return malloc(size); }
|
||||
void *MyMalloc2(size_t size);
|
||||
|
||||
@@ -53,3 +53,34 @@ void customAllocatorTests()
|
||||
double *dptr1 = MyMalloc1(33); // BAD -- Not a multiple of sizeof(double) [NOT DETECTED]
|
||||
double *dptr2 = MyMalloc2(33); // BAD -- Not a multiple of sizeof(double) [NOT DETECTED]
|
||||
}
|
||||
|
||||
// --- variable length data structures ---
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
typedef struct _MyVarStruct1 {
|
||||
size_t dataLen;
|
||||
uint8_t data[0];
|
||||
} MyVarStruct1;
|
||||
|
||||
typedef struct _MyVarStruct2 {
|
||||
size_t dataLen;
|
||||
uint8_t data[1];
|
||||
} MyVarStruct2;
|
||||
|
||||
typedef struct _MyVarStruct3 {
|
||||
size_t dataLen;
|
||||
uint8_t data[];
|
||||
} MyVarStruct3;
|
||||
|
||||
typedef struct _MyFixedStruct {
|
||||
size_t dataLen;
|
||||
uint8_t data[1024];
|
||||
} MyFixedStruct;
|
||||
|
||||
void varStructTests() {
|
||||
MyVarStruct1 *a = malloc(sizeof(MyVarStruct1) + 127); // GOOD
|
||||
MyVarStruct2 *b = malloc(sizeof(MyVarStruct2) + 127); // GOOD
|
||||
MyVarStruct3 *c = malloc(sizeof(MyVarStruct3) + 127); // GOOD
|
||||
MyFixedStruct *d = malloc(sizeof(MyFixedStruct) + 127); // BAD --- Not a multiple of sizeof(MyFixedStruct)
|
||||
}
|
||||
|
||||
@@ -23,3 +23,4 @@
|
||||
| test.cpp:424:2:425:2 | for(...;...;...) ... | test.cpp:424:18:424:23 | ... < ... | 1 | i | { ... } | i | return ... |
|
||||
| test.cpp:433:2:434:2 | for(...;...;...) ... | test.cpp:433:18:433:22 | 0 | 0 | | { ... } | 0 | return ... |
|
||||
| test.cpp:559:3:564:3 | while (...) ... | test.cpp:559:9:559:15 | call to getBool | | call to getBool | { ... } | call to getBool | ExprStmt |
|
||||
| test.cpp:574:3:579:3 | while (...) ... | test.cpp:574:10:574:16 | call to getBool | | call to getBool | { ... } | call to getBool | ExprStmt |
|
||||
|
||||
@@ -565,4 +565,31 @@ void test45() {
|
||||
|
||||
*rP = NULL;
|
||||
use(r); // GOOD
|
||||
}
|
||||
|
||||
void test46()
|
||||
{
|
||||
LinkedList *r, **rP = &r;
|
||||
|
||||
while (getBool())
|
||||
{
|
||||
LinkedList *s = nullptr;
|
||||
*rP = s;
|
||||
rP = &s->next;
|
||||
}
|
||||
|
||||
*rP = nullptr;
|
||||
use(r);
|
||||
}
|
||||
|
||||
namespace std {
|
||||
float remquo(float, float, int*);
|
||||
}
|
||||
|
||||
void test47() {
|
||||
float x = 1.0f;
|
||||
float y = 2.0f;
|
||||
int quo;
|
||||
std::remquo(x, y, &quo);
|
||||
use(quo); // GOOD
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
| test.cpp:92:5:92:31 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||
| test.cpp:93:15:93:41 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||
| test.cpp:96:10:96:36 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||
| test.cpp:151:9:151:24 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:152:15:152:18 | { ... } | This catch block |
|
||||
| test.cpp:199:15:199:35 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:201:16:201:19 | { ... } | This catch block |
|
||||
| test.cpp:212:14:212:34 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:213:34:213:36 | { ... } | This catch block |
|
||||
| test.cpp:246:17:246:31 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:247:8:247:12 | ! ... | This check |
|
||||
| test.cpp:160:9:160:24 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:161:15:161:18 | { ... } | This catch block |
|
||||
| test.cpp:229:15:229:35 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:231:16:231:19 | { ... } | This catch block |
|
||||
| test.cpp:242:14:242:34 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:243:34:243:36 | { ... } | This catch block |
|
||||
| test.cpp:276:17:276:31 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:277:8:277:12 | ! ... | This check |
|
||||
|
||||
@@ -136,6 +136,8 @@ void good_new_handles_nullptr() {
|
||||
return; // GOOD
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
void* operator new(std::size_t count, void*) noexcept;
|
||||
void* operator new[](std::size_t count, void*) noexcept;
|
||||
|
||||
@@ -146,18 +148,46 @@ struct Foo {
|
||||
operator bool();
|
||||
};
|
||||
|
||||
struct Bar {
|
||||
Bar();
|
||||
|
||||
operator bool();
|
||||
};
|
||||
|
||||
void bad_placement_new_with_exception_handling() {
|
||||
char buffer[1024];
|
||||
try { new (buffer) Foo; } // BAD
|
||||
|
||||
try { new (buffer) Foo; } // BAD (placement new should not fail)
|
||||
catch (...) { }
|
||||
}
|
||||
|
||||
void good_placement_new_with_exception_handling() {
|
||||
char buffer[1024];
|
||||
|
||||
try { new (buffer) Foo(42); } // GOOD: Foo constructor might throw
|
||||
catch (...) { }
|
||||
|
||||
try { new (buffer) Bar; } // GOOD: Bar constructor might throw
|
||||
catch (...) { }
|
||||
}
|
||||
|
||||
template<typename F> F *test_template_platement_new() {
|
||||
char buffer[1024];
|
||||
|
||||
try {
|
||||
return new (buffer) F; // GOOD: `F` constructor might throw (when `F` is `Bar`)
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void test_template_platement_new_caller() {
|
||||
test_template_platement_new<Foo>();
|
||||
test_template_platement_new<Bar>();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
int unknown_value_without_exceptions() noexcept;
|
||||
|
||||
void may_throw() {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.21
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.20
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user