Merge pull request #15047 from MathiasVP/add-puns-for-addresses-of-arguments

C++: Add `PostUpdateNode`s for addresses of outgoing arguments
This commit is contained in:
Mathias Vorreiter Pedersen
2023-12-12 13:55:13 +00:00
committed by GitHub
9 changed files with 317 additions and 207 deletions

View File

@@ -39,7 +39,7 @@ private newtype TIRDataFlowNode =
} or
TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
operand = any(FieldAddress fa).getObjectAddressOperand() and
indirectionIndex = [1 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
or
Ssa::isModifiableByCall(operand, indirectionIndex)
} or
@@ -436,7 +436,12 @@ class Node extends TIRDataFlowNode {
* `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
* a partial definition of `&x`).
*/
Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() }
Expr asPartialDefinition() {
exists(PartialDefinitionNode pdn | this = pdn |
pdn.getIndirectionIndex() > 0 and
result = pdn.getDefinedExpr()
)
}
/**
* Gets an upper bound on the type of this node.
@@ -563,11 +568,17 @@ private class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeI
Operand getOperand() { result = operand }
/** Gets the indirection index associated with this node. */
int getIndirectionIndex() { result = indirectionIndex }
override int getIndirectionIndex() { result = indirectionIndex }
override Location getLocationImpl() { result = operand.getLocation() }
final override Node getPreUpdateNode() { hasOperandAndIndex(result, operand, indirectionIndex) }
final override Node getPreUpdateNode() {
indirectionIndex > 0 and
hasOperandAndIndex(result, operand, indirectionIndex)
or
indirectionIndex = 0 and
result.asOperand() = operand
}
final override Expr getDefinedExpr() {
result = operand.getDef().getUnconvertedResultExpression()
@@ -836,12 +847,14 @@ class IndirectArgumentOutNode extends PostUpdateNodeImpl {
Function getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() }
override string toStringImpl() {
// This string should be unique enough to be helpful but common enough to
// avoid storing too many different strings.
result = this.getStaticCallTarget().getName() + " output argument"
or
not exists(this.getStaticCallTarget()) and
result = "output argument"
exists(string prefix | if indirectionIndex > 0 then prefix = "" else prefix = "pointer to " |
// This string should be unique enough to be helpful but common enough to
// avoid storing too many different strings.
result = prefix + this.getStaticCallTarget().getName() + " output argument"
or
not exists(this.getStaticCallTarget()) and
result = prefix + "output argument"
)
}
}
@@ -1699,6 +1712,10 @@ abstract class PostUpdateNode extends Node {
* ```
*/
abstract private class PartialDefinitionNode extends PostUpdateNode {
/** Gets the indirection index of this node. */
abstract int getIndirectionIndex();
/** Gets the expression that is partially defined by this node. */
abstract Expr getDefinedExpr();
}
@@ -1713,6 +1730,8 @@ abstract private class PartialDefinitionNode extends PostUpdateNode {
* `getVariableAccess()` equal to `x`.
*/
class DefinitionByReferenceNode extends IndirectArgumentOutNode {
DefinitionByReferenceNode() { this.getIndirectionIndex() > 0 }
/** Gets the unconverted argument corresponding to this node. */
Expr getArgument() { result = this.getAddressOperand().getDef().getUnconvertedResultExpression() }

View File

@@ -417,56 +417,34 @@ class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {
override CppType getLanguageType() { result = getResultLanguageType(call) }
}
/**
* Holds if the value pointed to by `operand` can potentially be
* modified be the caller.
*/
predicate isModifiableByCall(ArgumentOperand operand, int indirectionIndex) {
exists(CallInstruction call, int index, CppType type |
indirectionIndex = [1 .. countIndirectionsForCppType(type)] and
type = getLanguageType(operand) and
call.getArgumentOperand(index) = operand and
if index = -1
then
// A qualifier is "modifiable" if:
// 1. the member function is not const specified, or
// 2. the member function is `const` specified, but returns a pointer or reference
// type that is non-const.
//
// To see why this is necessary, consider the following function:
// ```
// struct C {
// void* data_;
// void* data() const { return data; }
// };
// ...
// C c;
// memcpy(c.data(), source, 16)
// ```
// the data pointed to by `c.data_` is potentially modified by the call to `memcpy` even though
// `C::data` has a const specifier. So we further place the restriction that the type returned
// by `call` should not be of the form `const T*` (for some deeply const type `T`).
if call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction
then
exists(PointerOrArrayOrReferenceType resultType |
resultType = call.getResultType() and
not resultType.isDeeplyConstBelow()
)
else any()
else
// An argument is modifiable if it's a non-const pointer or reference type.
isModifiableAt(type, indirectionIndex)
)
}
/**
* Holds if `t` is a pointer or reference type that supports at least `indirectionIndex` number
* of indirections, and the `indirectionIndex` indirection cannot be modfiied by passing a
* value of `t` to a function.
*/
private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
indirectionIndex = [1 .. countIndirectionsForCppType(cppType)] and
(
private module IsModifiableAtImpl {
/**
* Holds if the `indirectionIndex`'th dereference of a value of type
* `cppType` is a type that can be modified (either by modifying the value
* itself or one of its fields if it's a class type).
*
* For example, a value of type `const int* const` cannot be modified
* at any indirection index (because it's a constant pointer to constant
* data), and a value of type `int *const *` is modifiable at indirection index
* 2 only.
*
* A value of type `const S2* s2` where `s2` is
* ```cpp
* struct S { int x; }
* ```
* can be modified at indirection index 1. This is to ensure that we generate
* a `PostUpdateNode` for the argument corresponding to the `s2` parameter in
* an example such as:
* ```cpp
* void set_field(const S2* s2)
* {
* s2->s->x = 42;
* }
* ```
*/
bindingset[cppType, indirectionIndex]
pragma[inline_late]
private predicate impl(CppType cppType, int indirectionIndex) {
exists(Type pointerType, Type base, Type t |
pointerType = t.getUnderlyingType() and
pointerType = any(Indirection ind).getUnderlyingType() and
@@ -480,28 +458,114 @@ private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
// one of the members was modified.
exists(base.stripType().(Cpp::Class).getAField())
)
}
/**
* Holds if `cppType` is modifiable with an indirection index of at least 1.
*
* This predicate factored out into a separate predicate for two reasons:
* - This predicate needs to be recursive because, if a type is modifiable
* at indirection `i`, then it's also modifiable at indirection index `i+1`
* (because the pointer could be completely re-assigned at indirection `i`).
* - We special-case indirection index `0` so that pointer arguments that can
* be modified at some index always have a `PostUpdateNode` at indiretion
* index 0 even though the 0'th indirection can never be modified by a
* callee.
*/
private predicate isModifiableAtImplAtLeast1(CppType cppType, int indirectionIndex) {
indirectionIndex = [1 .. countIndirectionsForCppType(cppType)] and
(
impl(cppType, indirectionIndex)
or
// If the `indirectionIndex`'th dereference of a type can be modified
// then so can the `indirectionIndex + 1`'th dereference.
isModifiableAtImplAtLeast1(cppType, indirectionIndex - 1)
)
}
/**
* Holds if `cppType` is modifiable at indirection index 0.
*
* In reality, the 0'th indirection of a pointer (i.e., the pointer itself)
* can never be modified by a callee, but it is sometimes useful to be able
* to specify the value of the pointer, as its coming out of a function, as
* a source of dataflow since the shared library's reverse-read mechanism
* then ensures that field-flow is accounted for.
*/
private predicate isModifiableAtImplAt0(CppType cppType) { impl(cppType, 0) }
/**
* Holds if `t` is a pointer or reference type that supports at least
* `indirectionIndex` number of indirections, and the `indirectionIndex`
* indirection cannot be modfiied by passing a value of `t` to a function.
*/
private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
isModifiableAtImplAtLeast1(cppType, indirectionIndex)
or
// If the `indirectionIndex`'th dereference of a type can be modified
// then so can the `indirectionIndex + 1`'th dereference.
isModifiableAtImpl(cppType, indirectionIndex - 1)
)
indirectionIndex = 0 and
isModifiableAtImplAt0(cppType)
}
/**
* Holds if `t` is a type with at least `indirectionIndex` number of
* indirections, and the `indirectionIndex` indirection can be modified by
* passing a value of type `t` to a function function.
*/
bindingset[indirectionIndex]
predicate isModifiableAt(CppType cppType, int indirectionIndex) {
isModifiableAtImpl(cppType, indirectionIndex)
or
exists(PointerWrapper pw, Type t |
cppType.hasType(t, _) and
t.stripType() = pw and
not pw.pointsToConst()
)
}
/**
* Holds if the value pointed to by `operand` can potentially be
* modified be the caller.
*/
predicate isModifiableByCall(ArgumentOperand operand, int indirectionIndex) {
exists(CallInstruction call, int index, CppType type |
indirectionIndex = [0 .. countIndirectionsForCppType(type)] and
type = getLanguageType(operand) and
call.getArgumentOperand(index) = operand and
if index = -1
then
// A qualifier is "modifiable" if:
// 1. the member function is not const specified, or
// 2. the member function is `const` specified, but returns a pointer or reference
// type that is non-const.
//
// To see why this is necessary, consider the following function:
// ```
// struct C {
// void* data_;
// void* data() const { return data; }
// };
// ...
// C c;
// memcpy(c.data(), source, 16)
// ```
// the data pointed to by `c.data_` is potentially modified by the call to `memcpy` even though
// `C::data` has a const specifier. So we further place the restriction that the type returned
// by `call` should not be of the form `const T*` (for some deeply const type `T`).
if call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction
then
exists(PointerOrArrayOrReferenceType resultType |
resultType = call.getResultType() and
not resultType.isDeeplyConstBelow()
)
else any()
else
// An argument is modifiable if it's a non-const pointer or reference type.
isModifiableAt(type, indirectionIndex)
)
}
}
/**
* Holds if `t` is a type with at least `indirectionIndex` number of indirections,
* and the `indirectionIndex` indirection can be modified by passing a value of
* type `t` to a function function.
*/
bindingset[indirectionIndex]
predicate isModifiableAt(CppType cppType, int indirectionIndex) {
isModifiableAtImpl(cppType, indirectionIndex)
or
exists(PointerWrapper pw, Type t |
cppType.hasType(t, _) and
t.stripType() = pw and
not pw.pointsToConst()
)
}
import IsModifiableAtImpl
abstract class BaseSourceVariableInstruction extends Instruction {
/** Gets the base source variable accessed by this instruction. */

View File

@@ -16,7 +16,11 @@ import semmle.code.cpp.dataflow.new.DataFlow
import FlowAfterFree
import DoubleFree::PathGraph
predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
/**
* Holds if `n` is a dataflow node that represents a pointer going into a
* deallocation function, and `e` is the corresponding expression.
*/
predicate isFree(DataFlow::Node n, Expr e) { isFree(_, n, e, _) }
/**
* `dealloc1` is a deallocation expression and `e` is an expression such
@@ -28,7 +32,7 @@ predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
*/
bindingset[dealloc1, e]
predicate isExcludeFreePair(DeallocationExpr dealloc1, Expr e) {
exists(DeallocationExpr dealloc2 | isFree(_, e, dealloc2) |
exists(DeallocationExpr dealloc2 | isFree(_, _, e, dealloc2) |
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
@@ -42,7 +46,7 @@ module DoubleFree = FlowFromFree<isFree/2, isExcludeFreePair/2>;
from DoubleFree::PathNode source, DoubleFree::PathNode sink, DeallocationExpr dealloc, Expr e2
where
DoubleFree::flowPath(source, sink) and
isFree(source.getNode(), _, dealloc) and
isFree(source.getNode(), _, _, dealloc) and
isFree(sink.getNode(), e2)
select sink.getNode(), source, sink,
"Memory pointed to by '" + e2.toString() + "' may already have been freed by $@.", dealloc,

View File

@@ -50,12 +50,12 @@ predicate strictlyDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
module FlowFromFreeConfig implements DataFlow::StateConfigSig {
class FlowState instanceof Expr {
FlowState() { isFree(_, this, _) }
FlowState() { isFree(_, _, this, _) }
string toString() { result = super.toString() }
}
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, state, _) }
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, _, state, _) }
pragma[inline]
predicate isSink(DataFlow::Node sink, FlowState state) {
@@ -64,7 +64,7 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
DeallocationExpr dealloc
|
isASink(sink, e) and
isFree(source, state, dealloc) and
isFree(source, _, state, dealloc) and
e != state and
source.hasIndexInBlock(b1, i1) and
sink.hasIndexInBlock(b2, i2) and
@@ -94,14 +94,17 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
}
/**
* Holds if `n` is a dataflow node such that `n.asExpr() = e` and `e`
* is being freed by a deallocation expression `dealloc`.
* Holds if `outgoing` is a dataflow node that represents the pointer passed to
* `dealloc` after the call returns (i.e., the post-update node associated with
* the argument to `dealloc`), and `incoming` is the corresponding argument
* node going into `dealloc` (i.e., the pre-update node of `outgoing`).
*/
predicate isFree(DataFlow::Node n, Expr e, DeallocationExpr dealloc) {
predicate isFree(DataFlow::Node outgoing, DataFlow::Node incoming, Expr e, DeallocationExpr dealloc) {
exists(Expr conv |
e = conv.getUnconverted() and
conv = dealloc.getFreedExpr().getFullyConverted() and
conv = n.asConvertedExpr()
incoming = outgoing.(DataFlow::PostUpdateNode).getPreUpdateNode() and
conv = incoming.asConvertedExpr()
) and
// Ignore realloc functions
not exists(dealloc.(FunctionCall).getTarget().(AllocationFunction).getReallocPtrArg())

View File

@@ -30,7 +30,7 @@ private predicate externalCallNeverDereferences(FormattingFunctionCall call, int
}
predicate isUse0(Expr e) {
not isFree(_, e, _) and
not isFree(_, _, e, _) and
(
e = any(PointerDereferenceExpr pde).getOperand()
or
@@ -170,6 +170,6 @@ module UseAfterFree = FlowFromFree<isUse/2, isExcludeFreeUsePair/2>;
from UseAfterFree::PathNode source, UseAfterFree::PathNode sink, DeallocationExpr dealloc
where
UseAfterFree::flowPath(source, sink) and
isFree(source.getNode(), _, dealloc)
isFree(source.getNode(), _, _, dealloc)
select sink.getNode(), source, sink, "Memory may have been previously freed by $@.", dealloc,
dealloc.toString()

View File

@@ -1,52 +1,56 @@
edges
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
| test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a |
| test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
| test_free.cpp:83:12:83:12 | a | test_free.cpp:85:12:85:12 | a |
| test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a |
| test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:14:10:14:10 | a |
| test_free.cpp:30:10:30:10 | pointer to free output argument | test_free.cpp:31:27:31:27 | a |
| test_free.cpp:35:10:35:10 | pointer to free output argument | test_free.cpp:37:27:37:27 | a |
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:44:27:44:27 | pointer to free output argument | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:50:27:50:27 | pointer to free output argument | test_free.cpp:51:10:51:10 | a |
| test_free.cpp:69:10:69:10 | pointer to free output argument | test_free.cpp:72:14:72:14 | a |
| test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:85:12:85:12 | a |
| test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:103:10:103:10 | a |
| test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... |
| test_free.cpp:131:10:131:13 | pointer to free output argument | test_free.cpp:132:10:132:13 | access to array |
| test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a |
| test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a |
nodes
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
| test_free.cpp:30:10:30:10 | a | semmle.label | a |
| test_free.cpp:30:10:30:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:31:27:31:27 | a | semmle.label | a |
| test_free.cpp:35:10:35:10 | a | semmle.label | a |
| test_free.cpp:35:10:35:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:37:27:37:27 | a | semmle.label | a |
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
| test_free.cpp:42:27:42:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:44:27:44:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
| test_free.cpp:50:27:50:27 | a | semmle.label | a |
| test_free.cpp:50:27:50:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:51:10:51:10 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
| test_free.cpp:83:12:83:12 | a | semmle.label | a |
| test_free.cpp:83:12:83:12 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
| test_free.cpp:85:12:85:12 | a | semmle.label | a |
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
| test_free.cpp:101:10:101:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:103:10:103:10 | a | semmle.label | a |
| test_free.cpp:128:10:128:11 | * ... | semmle.label | * ... |
| test_free.cpp:128:10:128:11 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:129:10:129:11 | * ... | semmle.label | * ... |
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
| test_free.cpp:131:10:131:13 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:132:10:132:13 | access to array | semmle.label | access to array |
| test_free.cpp:152:27:152:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
| test_free.cpp:207:10:207:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
subpaths
#select
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:31:27:31:27 | a | test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:30:5:30:8 | call to free | call to free |
| test_free.cpp:37:27:37:27 | a | test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:35:5:35:8 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:51:10:51:10 | a | test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:50:22:50:25 | call to free | call to free |
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:85:12:85:12 | a | test_free.cpp:83:12:83:12 | a | test_free.cpp:85:12:85:12 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:83:5:83:13 | delete | delete |
| test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:31:27:31:27 | a | test_free.cpp:30:10:30:10 | pointer to free output argument | test_free.cpp:31:27:31:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:30:5:30:8 | call to free | call to free |
| test_free.cpp:37:27:37:27 | a | test_free.cpp:35:10:35:10 | pointer to free output argument | test_free.cpp:37:27:37:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:35:5:35:8 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | pointer to free output argument | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:51:10:51:10 | a | test_free.cpp:50:27:50:27 | pointer to free output argument | test_free.cpp:51:10:51:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:50:22:50:25 | call to free | call to free |
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | pointer to free output argument | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:85:12:85:12 | a | test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:85:12:85:12 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:83:5:83:13 | delete | delete |
| test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
| test_free.cpp:132:10:132:13 | access to array | test_free.cpp:131:10:131:13 | pointer to free output argument | test_free.cpp:132:10:132:13 | access to array | Memory pointed to by 'access to array' may already have been freed by $@. | test_free.cpp:131:5:131:8 | call to free | call to free |
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |

View File

@@ -1,65 +1,81 @@
edges
| test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a |
| test_free.cpp:11:10:11:10 | a | test_free.cpp:13:5:13:6 | * ... |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a |
| test_free.cpp:83:12:83:12 | a | test_free.cpp:84:5:84:5 | a |
| test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a |
| test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a |
| test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a |
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
| test_free.cpp:293:8:293:10 | buf | test_free.cpp:294:3:294:13 | ... = ... |
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a |
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... |
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:44:27:44:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:69:10:69:10 | pointer to free output argument | test_free.cpp:71:9:71:9 | a |
| test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:84:5:84:5 | a |
| test_free.cpp:90:10:90:10 | pointer to free output argument | test_free.cpp:91:5:91:5 | a |
| test_free.cpp:95:10:95:10 | pointer to free output argument | test_free.cpp:96:9:96:9 | a |
| test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:102:23:102:23 | a |
| test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:153:5:153:5 | a |
| test_free.cpp:233:14:233:15 | pointer to free output argument | test_free.cpp:236:9:236:10 | * ... |
| test_free.cpp:239:14:239:15 | pointer to free output argument | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:245:10:245:11 | pointer to free output argument | test_free.cpp:246:9:246:10 | * ... |
| test_free.cpp:277:8:277:8 | s indirection [post update] [buf] | test_free.cpp:278:12:278:12 | s indirection [buf] |
| test_free.cpp:277:8:277:13 | pointer to free output argument | test_free.cpp:277:8:277:8 | s indirection [post update] [buf] |
| test_free.cpp:278:12:278:12 | s indirection [buf] | test_free.cpp:278:15:278:17 | buf |
| test_free.cpp:282:8:282:8 | s indirection [post update] [buf] | test_free.cpp:283:12:283:12 | s indirection [buf] |
| test_free.cpp:282:8:282:12 | pointer to free output argument | test_free.cpp:282:8:282:8 | s indirection [post update] [buf] |
| test_free.cpp:283:12:283:12 | s indirection [buf] | test_free.cpp:283:14:283:16 | buf |
| test_free.cpp:293:8:293:10 | pointer to free output argument | test_free.cpp:294:3:294:13 | ... = ... |
| test_free.cpp:294:3:294:3 | s indirection [post update] [buf] | test_free.cpp:295:12:295:12 | s indirection [buf] |
| test_free.cpp:294:3:294:13 | ... = ... | test_free.cpp:294:3:294:3 | s indirection [post update] [buf] |
| test_free.cpp:295:12:295:12 | s indirection [buf] | test_free.cpp:295:14:295:16 | buf |
nodes
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
| 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 | * ... |
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
| test_free.cpp:42:27:42:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:44:27:44:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:71:9:71:9 | a | semmle.label | a |
| test_free.cpp:83:12:83:12 | a | semmle.label | a |
| test_free.cpp:83:12:83:12 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
| test_free.cpp:84:5:84:5 | a | semmle.label | a |
| test_free.cpp:90:10:90:10 | a | semmle.label | a |
| test_free.cpp:90:10:90:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:91:5:91:5 | a | semmle.label | a |
| test_free.cpp:95:10:95:10 | a | semmle.label | a |
| test_free.cpp:95:10:95:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:96:9:96:9 | a | semmle.label | a |
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
| test_free.cpp:101:10:101:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:102:23:102:23 | a | semmle.label | a |
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
| test_free.cpp:152:27:152:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:153:5:153:5 | a | semmle.label | a |
| test_free.cpp:233:14:233:15 | * ... | semmle.label | * ... |
| test_free.cpp:233:14:233:15 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:236:9:236:10 | * ... | semmle.label | * ... |
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
| test_free.cpp:239:14:239:15 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
| test_free.cpp:245:10:245:11 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
| test_free.cpp:293:8:293:10 | buf | semmle.label | buf |
| test_free.cpp:277:8:277:8 | s indirection [post update] [buf] | semmle.label | s indirection [post update] [buf] |
| test_free.cpp:277:8:277:13 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:278:12:278:12 | s indirection [buf] | semmle.label | s indirection [buf] |
| test_free.cpp:278:15:278:17 | buf | semmle.label | buf |
| test_free.cpp:282:8:282:8 | s indirection [post update] [buf] | semmle.label | s indirection [post update] [buf] |
| test_free.cpp:282:8:282:12 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:283:12:283:12 | s indirection [buf] | semmle.label | s indirection [buf] |
| test_free.cpp:283:14:283:16 | buf | semmle.label | buf |
| test_free.cpp:293:8:293:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:294:3:294:3 | s indirection [post update] [buf] | semmle.label | s indirection [post update] [buf] |
| test_free.cpp:294:3:294:13 | ... = ... | semmle.label | ... = ... |
| test_free.cpp:295:12:295:12 | s indirection [buf] | semmle.label | s indirection [buf] |
| test_free.cpp:295:14:295:16 | buf | semmle.label | buf |
subpaths
#select
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | a | 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 | a | 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 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:84:5:84:5 | a | test_free.cpp:83:12:83:12 | a | test_free.cpp:84:5:84:5 | a | Memory may have been previously freed by $@. | test_free.cpp:83:5:83:13 | delete | delete |
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
| test_free.cpp:96:9:96:9 | a | test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a | Memory may have been previously freed by $@. | test_free.cpp:95:5:95:8 | call to free | call to free |
| test_free.cpp:102:23:102:23 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a | Memory may have been previously freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
| test_free.cpp:295:14:295:16 | buf | test_free.cpp:293:8:293:10 | buf | test_free.cpp:295:14:295:16 | buf | Memory may have been previously freed by $@. | test_free.cpp:293:3:293:6 | call to free | call to free |
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:13:5:13:6 | * ... | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | pointer to free output argument | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:84:5:84:5 | a | test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:84:5:84:5 | a | Memory may have been previously freed by $@. | test_free.cpp:83:5:83:13 | delete | delete |
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | pointer to free output argument | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
| test_free.cpp:96:9:96:9 | a | test_free.cpp:95:10:95:10 | pointer to free output argument | test_free.cpp:96:9:96:9 | a | Memory may have been previously freed by $@. | test_free.cpp:95:5:95:8 | call to free | call to free |
| test_free.cpp:102:23:102:23 | a | test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:102:23:102:23 | a | Memory may have been previously freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | pointer to free output argument | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | pointer to free output argument | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | pointer to free output argument | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
| test_free.cpp:278:15:278:17 | buf | test_free.cpp:277:8:277:13 | pointer to free output argument | test_free.cpp:278:15:278:17 | buf | Memory may have been previously freed by $@. | test_free.cpp:277:3:277:6 | call to free | call to free |
| test_free.cpp:283:14:283:16 | buf | test_free.cpp:282:8:282:12 | pointer to free output argument | test_free.cpp:283:14:283:16 | buf | Memory may have been previously freed by $@. | test_free.cpp:282:3:282:6 | call to free | call to free |
| test_free.cpp:295:14:295:16 | buf | test_free.cpp:293:8:293:10 | pointer to free output argument | test_free.cpp:295:14:295:16 | buf | Memory may have been previously freed by $@. | test_free.cpp:293:3:293:6 | call to free | call to free |

View File

@@ -126,10 +126,10 @@ void test_ptr_deref(void ** a) {
free(*a);
*a = malloc(10);
free(*a); // GOOD
free(*a); // BAD [NOT DETECTED]
free(*a); // BAD
*a = malloc(10);
free(a[0]); // GOOD
free(a[1]); // GOOD
free(a[1]); // GOOD [FALSE POSITIVE]
}
struct list {
@@ -275,12 +275,12 @@ struct MyStruct {
void test_free_struct(MyStruct* s) {
free(s->buf);
char c = s->buf[0]; // BAD [FALSE NEGATIVE]
char c = s->buf[0]; // BAD
}
void test_free_struct2(MyStruct s) {
free(s.buf);
char c = s.buf[0]; // BAD [FALSE NEGATIVE]
char c = s.buf[0]; // BAD
}
void test_free_struct3(MyStruct s) {

View File

@@ -1,51 +1,51 @@
edges
| test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data |
| test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data |
| test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data |
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
| test.cpp:164:9:164:9 | c | test.cpp:165:2:165:2 | c |
| test.cpp:164:9:164:9 | c | test.cpp:166:3:166:4 | * ... |
| test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data |
| test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data |
| test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data |
| test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data |
| test.cpp:216:9:216:9 | x | test.cpp:217:6:217:6 | x |
| test.cpp:39:7:39:10 | pointer to free output argument | test.cpp:41:6:41:9 | data |
| test.cpp:75:7:75:10 | pointer to free output argument | test.cpp:79:7:79:10 | data |
| test.cpp:106:7:106:10 | pointer to free output argument | test.cpp:108:6:108:9 | data |
| test.cpp:116:7:116:10 | pointer to free output argument | test.cpp:119:6:119:9 | data |
| test.cpp:127:7:127:10 | pointer to free output argument | test.cpp:130:6:130:9 | data |
| test.cpp:164:9:164:9 | pointer to operator delete output argument | test.cpp:165:2:165:2 | c |
| test.cpp:164:9:164:9 | pointer to operator delete output argument | test.cpp:166:3:166:4 | * ... |
| test.cpp:181:7:181:10 | pointer to free output argument | test.cpp:186:6:186:9 | data |
| test.cpp:192:7:192:10 | pointer to free output argument | test.cpp:197:6:197:9 | data |
| test.cpp:203:7:203:10 | pointer to free output argument | test.cpp:209:6:209:9 | data |
| test.cpp:207:8:207:11 | pointer to free output argument | test.cpp:209:6:209:9 | data |
| test.cpp:216:9:216:9 | pointer to operator delete output argument | test.cpp:217:6:217:6 | x |
nodes
| test.cpp:39:7:39:10 | data | semmle.label | data |
| test.cpp:39:7:39:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:41:6:41:9 | data | semmle.label | data |
| test.cpp:75:7:75:10 | data | semmle.label | data |
| test.cpp:75:7:75:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:79:7:79:10 | data | semmle.label | data |
| test.cpp:106:7:106:10 | data | semmle.label | data |
| test.cpp:106:7:106:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:108:6:108:9 | data | semmle.label | data |
| test.cpp:116:7:116:10 | data | semmle.label | data |
| test.cpp:116:7:116:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:119:6:119:9 | data | semmle.label | data |
| test.cpp:127:7:127:10 | data | semmle.label | data |
| test.cpp:127:7:127:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:130:6:130:9 | data | semmle.label | data |
| test.cpp:164:9:164:9 | c | semmle.label | c |
| test.cpp:164:9:164:9 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
| test.cpp:165:2:165:2 | c | semmle.label | c |
| test.cpp:166:3:166:4 | * ... | semmle.label | * ... |
| test.cpp:181:7:181:10 | data | semmle.label | data |
| test.cpp:181:7:181:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:186:6:186:9 | data | semmle.label | data |
| test.cpp:192:7:192:10 | data | semmle.label | data |
| test.cpp:192:7:192:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:197:6:197:9 | data | semmle.label | data |
| test.cpp:203:7:203:10 | data | semmle.label | data |
| test.cpp:207:8:207:11 | data | semmle.label | data |
| test.cpp:203:7:203:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:207:8:207:11 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:209:6:209:9 | data | semmle.label | data |
| test.cpp:209:6:209:9 | data | semmle.label | data |
| test.cpp:216:9:216:9 | x | semmle.label | x |
| test.cpp:216:9:216:9 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
| test.cpp:217:6:217:6 | x | semmle.label | x |
subpaths
#select
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
| test.cpp:165:2:165:2 | c | test.cpp:164:9:164:9 | c | test.cpp:165:2:165:2 | c | Memory may have been previously freed by $@. | test.cpp:164:2:164:10 | delete | delete |
| test.cpp:166:3:166:4 | * ... | test.cpp:164:9:164:9 | c | test.cpp:166:3:166:4 | * ... | Memory may have been previously freed by $@. | test.cpp:164:2:164:10 | delete | delete |
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |
| test.cpp:217:6:217:6 | x | test.cpp:216:9:216:9 | x | test.cpp:217:6:217:6 | x | Memory may have been previously freed by $@. | test.cpp:216:2:216:9 | delete | delete |
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | pointer to free output argument | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | pointer to free output argument | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | pointer to free output argument | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | pointer to free output argument | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | pointer to free output argument | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
| test.cpp:165:2:165:2 | c | test.cpp:164:9:164:9 | pointer to operator delete output argument | test.cpp:165:2:165:2 | c | Memory may have been previously freed by $@. | test.cpp:164:2:164:10 | delete | delete |
| test.cpp:166:3:166:4 | * ... | test.cpp:164:9:164:9 | pointer to operator delete output argument | test.cpp:166:3:166:4 | * ... | Memory may have been previously freed by $@. | test.cpp:164:2:164:10 | delete | delete |
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | pointer to free output argument | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | pointer to free output argument | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | pointer to free output argument | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | pointer to free output argument | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |
| test.cpp:217:6:217:6 | x | test.cpp:216:9:216:9 | pointer to operator delete output argument | test.cpp:217:6:217:6 | x | Memory may have been previously freed by $@. | test.cpp:216:2:216:9 | delete | delete |