Merge branch 'main' into calumgrant/bmn/wrong-type-format-arg-linkage

This commit is contained in:
Jeroen Ketema
2025-02-03 11:23:27 +01:00
committed by GitHub
645 changed files with 34917 additions and 13475 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
description: Mix typedefs and usings
compatibility: full
usertypes.rel: run usertypes.qlo
usertype_alias_kind.rel: delete

View File

@@ -0,0 +1,20 @@
class UserType extends @usertype {
string toString() { none() }
}
int getTyperefKind(UserType usertype) {
usertype_alias_kind(usertype, 0) and
result = 5
or
usertype_alias_kind(usertype, 1) and
result = 14
}
bindingset[kind]
int getKind(UserType usertype, int kind) {
if kind = 18 then result = getTyperefKind(usertype) else result = kind
}
from UserType usertype, string name, int kind
where usertypes(usertype, name, kind)
select usertype, name, getKind(usertype, kind)

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* Deleted the deprecated `getAllocatorCall` predicate from `DeleteOrDeleteArrayExpr`, use `getDeallocatorCall` instead.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* A new predicate `getOffsetInClass` was added to the `Field` class, which computes the byte offset of a field relative to a given `Class`.

View File

@@ -87,11 +87,11 @@ module LiteralAlgorithmTracerConfig implements DataFlow::ConfigSig {
// False positives in OpenSSL also observed for CRYPTO_strndup (filtering any CRYPTO_* function)
// due to setting a null byte in the string
(
isPossibleOpenSSLFunction(source.getEnclosingCallable())
isPossibleOpenSSLFunction(source.getFunction())
implies
(
not source.getEnclosingCallable().getName().matches("OBJ_%") and
not source.getEnclosingCallable().getName().matches("CRYPTO_%")
not source.getFunction().getName().matches("OBJ_%") and
not source.getFunction().getName().matches("CRYPTO_%")
)
)
}

View File

@@ -5,6 +5,30 @@
import semmle.code.cpp.Variable
import semmle.code.cpp.Enum
private predicate hasAFieldWithOffset(Class c, Field f, int offset) {
// Base case: `f` is a field in `c`.
f = c.getAField() and
offset = f.getByteOffset() and
not f.getUnspecifiedType().(Class).hasDefinition()
or
// Otherwise, we find the struct that is a field of `c` which then has
// the field `f` as a member.
exists(Field g |
g = c.getAField() and
// Find the field with the largest offset that's less than or equal to
// offset. That's the struct we need to search recursively.
g =
max(Field cand, int candOffset |
cand = c.getAField() and
candOffset = cand.getByteOffset() and
offset >= candOffset
|
cand order by candOffset
) and
hasAFieldWithOffset(g.getUnspecifiedType(), f, offset - g.getByteOffset())
)
}
/**
* A C structure member or C++ non-static member variable. For example the
* member variable `m` in the following code (but not `s`):
@@ -76,6 +100,27 @@ class Field extends MemberVariable {
rank[result + 1](int index | cls.getCanonicalMember(index).(Field).isInitializable())
)
}
/**
* Gets the offset (in bytes) of this field starting at `c`.
*
* For example, consider:
* ```cpp
* struct S1 {
* int a;
* void* b;
* };
*
* struct S2 {
* S1 s1;
* char c;
* };
* ```
* If `f` represents the field `s1` and `c` represents the class `S2` then
* `f.getOffsetInClass(S2) = 0` holds. Likewise, if `f` represents the
* field `a`, then `f.getOffsetInClass(c) = 0` holds.
*/
int getOffsetInClass(Class c) { hasAFieldWithOffset(c, this, result) }
}
/**

View File

@@ -13,7 +13,7 @@ private import semmle.code.cpp.internal.ResolveClass
* ```
*/
class TypedefType extends UserType {
TypedefType() { usertypes(underlyingElement(this), _, [5, 14]) }
TypedefType() { usertypes(underlyingElement(this), _, 18) }
/**
* Gets the base type of this typedef type.
@@ -54,7 +54,7 @@ class TypedefType extends UserType {
* ```
*/
class CTypedefType extends TypedefType {
CTypedefType() { usertypes(underlyingElement(this), _, 5) }
CTypedefType() { usertype_alias_kind(underlyingElement(this), 0) }
override string getAPrimaryQlClass() { result = "CTypedefType" }
@@ -70,7 +70,7 @@ class CTypedefType extends TypedefType {
* ```
*/
class UsingAliasTypedefType extends TypedefType {
UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) }
UsingAliasTypedefType() { usertype_alias_kind(underlyingElement(this), 1) }
override string getAPrimaryQlClass() { result = "UsingAliasTypedefType" }

View File

@@ -47,10 +47,16 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
else result = this.getADeclarationLocation()
}
pragma[nomagic]
private TypeDeclarationEntry getADeclarationEntryBase() {
type_decls(underlyingElement(result), unresolveElement(this), _)
}
override TypeDeclarationEntry getADeclarationEntry() {
if type_decls(_, unresolveElement(this), _)
then type_decls(underlyingElement(result), unresolveElement(this), _)
else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry())
pragma[only_bind_into](result) = pragma[only_bind_into](this).getADeclarationEntryBase()
or
not exists(this.getADeclarationEntryBase()) and
exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry())
}
override Location getADeclarationLocation() { result = this.getADeclarationEntry().getLocation() }

View File

@@ -24,6 +24,74 @@ predicate memberMayBeVarSize(Class c, MemberVariable v) {
exists(ArrayType t | t = v.getUnspecifiedType() | not t.getArraySize() > 1)
}
/**
* Given a chain of accesses of the form `x.f1.f2...fn` this
* predicate gives the type of `x`. Note that `x` may be an implicit
* `this` expression.
*/
private Class getRootType(FieldAccess fa) {
// If the object is accessed inside a member function then the root will
// be a(n implicit) `this`. And the root type will be the type of `this`.
exists(VariableAccess root |
root = fa.getQualifier*() and
result =
root.getQualifier()
.(ThisExpr)
.getUnspecifiedType()
.(PointerType)
.getBaseType()
.getUnspecifiedType()
)
or
// Otherwise, if this is not inside a member function there will not be
// a(n implicit) `this`. And the root type is the type of the outermost
// access.
exists(VariableAccess root |
root = fa.getQualifier+() and
not exists(root.getQualifier()) and
result = root.getUnspecifiedType()
)
}
/**
* Gets the size of the buffer access at `va`.
*/
private int getSize(VariableAccess va) {
exists(Variable v | va.getTarget() = v |
// If `v` is not a field then the size of the buffer is just
// the size of the type of `v`.
exists(Type t |
t = v.getUnspecifiedType() and
not v instanceof Field and
not t instanceof ReferenceType and
result = t.getSize()
)
or
exists(Class c |
// Otherwise, we find the "outermost" object and compute the size
// as the difference between the size of the type of the "outermost
// object" and the offset of the field relative to that type.
// For example, consider the following structs:
// ```
// struct S {
// uint32_t x;
// uint32_t y;
// };
// struct S2 {
// S s;
// uint32_t z;
// };
// ```
// Given an object `S2 s2` the size of the buffer `&s2.s.y`
// is the size of the base object type (i.e., `S2`) minutes the offset
// of `y` relative to the type `S2` (i.e., `4`). So the size of the
// buffer is `12 - 4 = 8`.
c = getRootType(va) and
result = c.getSize() - v.(Field).getOffsetInClass(c)
)
)
}
/**
* Holds if `bufferExpr` is an allocation-like expression.
*
@@ -54,22 +122,11 @@ private int isSource(Expr bufferExpr, Element why) {
result = bufferExpr.(AllocationExpr).getSizeBytes() and
why = bufferExpr
or
exists(Type bufferType |
exists(Variable v |
v = why and
// buffer is the address of a variable
why = bufferExpr.(AddressOfExpr).getAddressable() and
bufferType = why.(Variable).getUnspecifiedType() and
result = bufferType.getSize() and
not bufferType instanceof ReferenceType and
not any(Union u).getAMemberVariable() = why
)
or
exists(Union bufferType |
// buffer is the address of a union member; in this case, we
// take the size of the union itself rather the union member, since
// it's usually OK to access that amount (e.g. clearing with memset).
why = bufferExpr.(AddressOfExpr).getAddressable() and
bufferType.getAMemberVariable() = why and
result = bufferType.getSize()
result = getSize(bufferExpr.(AddressOfExpr).getOperand())
)
}

View File

@@ -102,49 +102,76 @@ abstract private class GuardConditionImpl extends Expr {
this.valueControls(controlled, any(BooleanValue bv | bv.getValue() = testIsTrue))
}
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
/**
* Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this
* expression evaluates to `testIsTrue`. Note that there's a 4-argument
* ("unary") and a 5-argument ("binary") version of this predicate (see `comparesEq`).
*/
pragma[inline]
abstract predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue);
/**
* Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
* If `isLessThan = false` then this implies `left >= right + k`.
* If `isLessThan = false` then this implies `left >= right + k`. Note that there's a 4-argument
* ("unary") and a 5-argument ("binary") version of this predicate (see `comparesEq`).
*/
pragma[inline]
abstract predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan);
/**
* Holds if (determined by this guard) `e < k` evaluates to `isLessThan` if
* this expression evaluates to `value`.
* this expression evaluates to `value`. Note that there's a 4-argument
* ("unary") and a 5-argument ("binary") version of this predicate (see `comparesEq`).
*/
pragma[inline]
abstract predicate comparesLt(Expr e, int k, boolean isLessThan, AbstractValue value);
/**
* Holds if (determined by this guard) `e < k` must be `isLessThan` in `block`.
* If `isLessThan = false` then this implies `e >= k`.
* If `isLessThan = false` then this implies `e >= k`. Note that there's a 4-argument
* ("unary") and a 5-argument ("binary") version of this predicate (see `comparesEq`).
*/
pragma[inline]
abstract predicate ensuresLt(Expr e, int k, BasicBlock block, boolean isLessThan);
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
/**
* Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this
* expression evaluates to `testIsTrue`. Note that there's a 4-argument ("unary") and a
* 5-argument ("binary") version of `comparesEq` and they are not equivalent:
* - the unary version is suitable for guards where there is no expression representing the
* right-hand side, such as `if (x)`, and also works for equality with an integer constant
* (such as `if (x == k)`).
* - the binary version is the more general case for comparison of any expressions (not
* necessarily integer).
*/
pragma[inline]
abstract predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue);
/**
* Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
* If `areEqual = false` then this implies `left != right + k`.
* If `areEqual = false` then this implies `left != right + k`. Note that there's a 4-argument
* ("unary") and a 5-argument ("binary") version of this predicate (see `comparesEq`).
*/
pragma[inline]
abstract predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual);
/** Holds if (determined by this guard) `e == k` evaluates to `areEqual` if this expression evaluates to `value`. */
/**
* Holds if (determined by this guard) `e == k` evaluates to `areEqual` if this expression
* evaluates to `value`. Note that there's a 4-argument ("unary") and a 5-argument ("binary")
* version of `comparesEq` and they are not equivalent:
* - the unary version is suitable for guards where there is no expression representing the
* right-hand side, such as `if (x)`, and also works for equality with an integer constant
* (such as `if (x == k)`).
* - the binary version is the more general case for comparison of any expressions (not
* necessarily integer).
*/
pragma[inline]
abstract predicate comparesEq(Expr e, int k, boolean areEqual, AbstractValue value);
/**
* Holds if (determined by this guard) `e == k` must be `areEqual` in `block`.
* If `areEqual = false` then this implies `e != k`.
* If `areEqual = false` then this implies `e != k`. Note that there's a 4-argument
* ("unary") and a 5-argument ("binary") version of this predicate (see `comparesEq`).
*/
pragma[inline]
abstract predicate ensuresEq(Expr e, int k, BasicBlock block, boolean areEqual);
@@ -981,7 +1008,8 @@ private module Cached {
or
exists(CompareValueNumber cmp, Operand left, Operand right, AbstractValue v |
test = cmp and
cmp.hasOperands(left, right) and
pragma[only_bind_into](cmp)
.hasOperands(pragma[only_bind_into](left), pragma[only_bind_into](right)) and
isConvertedBool(left.getDef()) and
int_value(right.getDef()) = 0 and
unary_compares_eq(valueNumberOfOperand(left), op, k, areEqual, v)

View File

@@ -1110,11 +1110,6 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
expr_deallocator(underlyingElement(this), unresolveElement(result), _)
}
/**
* DEPRECATED: use `getDeallocatorCall` instead.
*/
deprecated FunctionCall getAllocatorCall() { result = this.getChild(0) }
/**
* Gets the call to a non-default `operator delete`/`delete[]` that deallocates storage, if any.
*

View File

@@ -152,7 +152,7 @@ private module VirtualDispatch {
ReturnNode node, ReturnKind kind, DataFlowCallable callable
) {
node.getKind() = kind and
node.getEnclosingCallable() = callable.getUnderlyingCallable()
node.getFunction() = callable.getUnderlyingCallable()
}
/** Call through a function pointer. */

View File

@@ -333,9 +333,7 @@ private module IndirectInstructions {
import IndirectInstructions
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) {
result.getUnderlyingCallable() = n.getEnclosingCallable()
}
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
@@ -1012,9 +1010,7 @@ class CastNode extends Node {
cached
private newtype TDataFlowCallable =
TSourceCallable(Cpp::Declaration decl) {
not decl instanceof FlowSummaryImpl::Public::SummarizedCallable
} or
TSourceCallable(Cpp::Declaration decl) or
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
/**
@@ -1127,7 +1123,21 @@ class DataFlowCall extends TDataFlowCall {
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
DataFlowCallable getStaticCallTarget() { none() }
Function getStaticCallSourceTarget() { none() }
/**
* Gets the target of this call. If a summarized callable exists for the
* target this is chosen, and otherwise the callable is the implementation
* from the source code.
*/
DataFlowCallable getStaticCallTarget() {
exists(Function target | target = this.getStaticCallSourceTarget() |
not exists(TSummarizedCallable(target)) and
result.asSourceCallable() = target
or
result.asSummarizedCallable() = target
)
}
/**
* Gets the `index`'th argument operand. The qualifier is considered to have index `-1`.
@@ -1173,14 +1183,12 @@ private class NormalCall extends DataFlowCall, TNormalCall {
override CallTargetOperand getCallTargetOperand() { result = call.getCallTargetOperand() }
override DataFlowCallable getStaticCallTarget() {
result.getUnderlyingCallable() = call.getStaticCallTarget()
}
override Function getStaticCallSourceTarget() { result = call.getStaticCallTarget() }
override ArgumentOperand getArgumentOperand(int index) { result = call.getArgumentOperand(index) }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = call.getEnclosingFunction()
result.asSourceCallable() = call.getEnclosingFunction()
}
override string toString() { result = call.toString() }
@@ -1331,7 +1339,12 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
(
call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode() or
call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode()
or
// No need to infer a lambda call if we already have a static dispatch target.
// We only need to check this in the disjunct since a `SummaryCall` never
// has a result for `getStaticCallTarget`.
not exists(call.getStaticCallTarget()) and
call.asCallInstruction().getCallTargetOperand() = receiver.asOperand()
) and
exists(kind)

View File

@@ -146,7 +146,7 @@ class Node extends TIRDataFlowNode {
/**
* INTERNAL: Do not use.
*/
Declaration getEnclosingCallable() { none() } // overridden in subclasses
DataFlowCallable getEnclosingCallable() { none() } // overridden in subclasses
/** Gets the function to which this node belongs, if any. */
Declaration getFunction() { none() } // overridden in subclasses
@@ -508,7 +508,9 @@ private class Node0 extends Node, TNode0 {
Node0() { this = TNode0(node) }
override Declaration getEnclosingCallable() { result = node.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = node.getEnclosingCallable()
}
override Declaration getFunction() { result = node.getFunction() }
@@ -573,7 +575,9 @@ class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
override Declaration getFunction() { result = operand.getUse().getEnclosingFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result = this.getPreUpdateNode().getEnclosingCallable()
}
/** Gets the operand associated with this node. */
Operand getOperand() { result = operand }
@@ -626,7 +630,9 @@ class SsaPhiNode extends Node, TSsaPhiNode {
/** Gets the phi node associated with this node. */
Ssa::PhiNode getPhiNode() { result = phi }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
@@ -709,7 +715,9 @@ class SsaPhiInputNode extends Node, TSsaPhiInputNode {
/** Gets the basic block in which this input originates. */
IRBlock getBlock() { result = block }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
@@ -738,7 +746,9 @@ class SsaIteratorNode extends Node, TSsaIteratorNode {
/** Gets the phi node associated with this node. */
IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = node.getFunction() }
@@ -773,7 +783,9 @@ class SideEffectOperandNode extends Node instanceof IndirectOperand {
int getArgumentIndex() { result = argumentIndex }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = call.getEnclosingFunction() }
@@ -794,7 +806,9 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
/** Gets the underlying SSA use. */
Ssa::GlobalUse getGlobalUse() { result = globalUse }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
@@ -824,7 +838,9 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
/** Gets the underlying SSA definition. */
Ssa::GlobalDef getGlobalDef() { result = globalDef }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = globalDef.getIRFunction().getFunction() }
@@ -855,7 +871,9 @@ class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
BodyLessParameterNodeImpl() { this = TBodyLessParameterNodeImpl(p, indirectionIndex) }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = p.getFunction() }
@@ -901,7 +919,9 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
* Gets the enclosing callable. For a `FlowSummaryNode` this is always the
* summarized function this node is part of.
*/
override Declaration getEnclosingCallable() { result = this.getSummarizedCallable() }
override DataFlowCallable getEnclosingCallable() {
result.asSummarizedCallable() = this.getSummarizedCallable()
}
override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
@@ -922,7 +942,7 @@ class IndirectReturnNode extends Node {
.hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _)
}
override Declaration getEnclosingCallable() { result = this.getFunction() }
override SourceCallable getEnclosingCallable() { result.asSourceCallable() = this.getFunction() }
/**
* Holds if this node represents the value that is returned to the caller
@@ -1116,11 +1136,11 @@ private module RawIndirectNodes {
/** Gets the underlying indirection index. */
int getIndirectionIndex() { result = indirectionIndex }
override Declaration getFunction() {
result = this.getOperand().getDef().getEnclosingFunction()
}
override Declaration getFunction() { result = node.getFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = node.getEnclosingCallable()
}
override predicate isGLValue() { this.getOperand().isGLValue() }
@@ -1162,9 +1182,11 @@ private module RawIndirectNodes {
/** Gets the underlying indirection index. */
int getIndirectionIndex() { result = indirectionIndex }
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
override Declaration getFunction() { result = node.getFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = node.getEnclosingCallable()
}
override predicate isGLValue() { this.getInstruction().isGLValue() }
@@ -1264,7 +1286,9 @@ class FinalParameterNode extends Node, TFinalParameterNode {
override Declaration getFunction() { result = p.getFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override DataFlowType getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
@@ -1306,7 +1330,29 @@ abstract private class AbstractParameterNode extends Node {
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
abstract predicate isParameterOf(DataFlowCallable f, ParameterPosition pos);
predicate isSourceParameterOf(Function f, ParameterPosition pos) { none() }
/**
* Holds if this node is the parameter of `sc` at the specified position. The
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
predicate isSummaryParameterOf(
FlowSummaryImpl::Public::SummarizedCallable sc, ParameterPosition pos
) {
none()
}
/**
* Holds if this node is the parameter of `c` at the specified position. The
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
final predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.isSummaryParameterOf(c.asSummarizedCallable(), pos)
or
this.isSourceParameterOf(c.asSourceCallable(), pos)
}
/** Gets the `Parameter` associated with this node, if it exists. */
Parameter getParameter() { none() } // overridden by subclasses
@@ -1362,12 +1408,14 @@ private class IndirectInstructionParameterNode extends AbstractIndirectParameter
/** Gets the parameter whose indirection is initialized. */
override Parameter getParameter() { result = init.getParameter() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = init.getEnclosingFunction() }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
this.getEnclosingCallable() = f.getUnderlyingCallable() and
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
this.getFunction() = f and
exists(int argumentIndex, int indirectionIndex |
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
@@ -1424,9 +1472,8 @@ private class ExplicitParameterInstructionNode extends AbstractExplicitParameter
{
ExplicitParameterInstructionNode() { exists(instr.getParameter()) }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
f.getUnderlyingCallable().(Function).getParameter(pos.(DirectPosition).getIndex()) =
instr.getParameter()
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
f.getParameter(pos.(DirectPosition).getIndex()) = instr.getParameter()
}
override string toStringImpl() { result = instr.getParameter().toString() }
@@ -1440,9 +1487,9 @@ class ThisParameterInstructionNode extends AbstractExplicitParameterNode,
{
ThisParameterInstructionNode() { instr.getIRVariable() instanceof IRThisVariable }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
pos.(DirectPosition).getIndex() = -1 and
instr.getEnclosingFunction() = f.getUnderlyingCallable()
instr.getEnclosingFunction() = f
}
override string toStringImpl() { result = "this" }
@@ -1460,8 +1507,10 @@ class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
}
override predicate isParameterOf(DataFlowCallable c, ParameterPosition p) {
c.getUnderlyingCallable() = this.getSummarizedCallable() and
override predicate isSummaryParameterOf(
FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p
) {
c = this.getSummarizedCallable() and
p = this.getPosition()
}
}
@@ -1471,12 +1520,9 @@ private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
{
DirectBodyLessParameterNode() { indirectionIndex = 0 }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
exists(Function func |
this.getFunction() = func and
f.asSourceCallable() = func and
func.getParameter(pos.(DirectPosition).getIndex()) = p
)
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
this.getFunction() = f and
f.getParameter(pos.(DirectPosition).getIndex()) = p
}
override Parameter getParameter() { result = p }
@@ -1487,12 +1533,11 @@ private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNod
{
IndirectBodyLessParameterNode() { not this instanceof DirectBodyLessParameterNode }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
exists(Function func, int argumentPosition |
this.getFunction() = func and
f.asSourceCallable() = func and
indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex) and
func.getParameter(argumentPosition) = p
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
exists(int argumentPosition |
this.getFunction() = f and
f.getParameter(argumentPosition) = p and
indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex)
)
}
@@ -1605,13 +1650,13 @@ class VariableNode extends Node, TGlobalLikeVariableNode {
override Declaration getFunction() { none() }
override Declaration getEnclosingCallable() {
override DataFlowCallable getEnclosingCallable() {
// When flow crosses from one _enclosing callable_ to another, the
// interprocedural data-flow library discards call contexts and inserts a
// node in the big-step relation used for human-readable path explanations.
// Therefore we want a distinct enclosing callable for each `VariableNode`,
// and that can be the `Variable` itself.
result = v
result.asSourceCallable() = v
}
override DataFlowType getType() {

View File

@@ -587,8 +587,8 @@ module ProductFlow {
pragma[nomagic]
private predicate interprocEdge1(
Declaration predDecl, Declaration succDecl, Flow1::PathNode pred1, Flow1::PathNode succ1,
TKind kind
DataFlowCallable predDecl, DataFlowCallable succDecl, Flow1::PathNode pred1,
Flow1::PathNode succ1, TKind kind
) {
Flow1::PathGraph::edges(pred1, succ1, _, _) and
predDecl != succDecl and
@@ -607,8 +607,8 @@ module ProductFlow {
pragma[nomagic]
private predicate interprocEdge2(
Declaration predDecl, Declaration succDecl, Flow2::PathNode pred2, Flow2::PathNode succ2,
TKind kind
DataFlowCallable predDecl, DataFlowCallable succDecl, Flow2::PathNode pred2,
Flow2::PathNode succ2, TKind kind
) {
Flow2::PathGraph::edges(pred2, succ2, _, _) and
predDecl != succDecl and
@@ -628,7 +628,7 @@ module ProductFlow {
private predicate interprocEdgePair(
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode succ1, Flow2::PathNode succ2
) {
exists(Declaration predDecl, Declaration succDecl, TKind kind |
exists(DataFlowCallable predDecl, DataFlowCallable succDecl, TKind kind |
interprocEdge1(predDecl, succDecl, pred1, succ1, kind) and
interprocEdge2(predDecl, succDecl, pred2, succ2, kind)
)

View File

@@ -1,5 +1,6 @@
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
@@ -8,7 +9,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
* guaranteed to be side-effect free.
*/
private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction,
SideEffectFunction
SideEffectFunction, DataFlowFunction
{
PureStrFunction() {
this.hasGlobalOrStdOrBslName([
@@ -25,23 +26,48 @@ private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunctio
this.getParameter(bufParam).getUnspecifiedType() instanceof PointerType
}
/** Holds if `i` is a locale parameter that does not carry taint. */
private predicate isLocaleParameter(ParameterIndex i) {
this.getName().matches("%\\_l") and i + 1 = this.getNumberOfParameters()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// For these functions we add taint flow according to the following rules:
// 1. If the parameter is of a pointer type then there is taint from the
// indirection of the parameter. Otherwise, there is taint from the
// parameter.
// 2. If the return value is of a pointer type then there is taint to the
// indirection of the return. Otherwise, there is taint to the return.
exists(ParameterIndex i |
(
input.isParameter(i) and
exists(this.getParameter(i))
or
input.isParameterDeref(i) and
this.getParameter(i).getUnspecifiedType() instanceof PointerType
) and
exists(this.getParameter(i)) and
// Functions that end with _l also take a locale argument (always as the last argument),
// and we don't want taint from those arguments.
(not this.getName().matches("%\\_l") or exists(this.getParameter(i + 1)))
not this.isLocaleParameter(i)
|
if this.getParameter(i).getUnspecifiedType() instanceof PointerType
then input.isParameterDeref(i)
else input.isParameter(i)
) and
(
output.isReturnValueDeref() and
this.getUnspecifiedType() instanceof PointerType
or
if this.getUnspecifiedType() instanceof PointerType
then output.isReturnValueDeref()
else output.isReturnValue()
)
or
// If there is taint flow from *input to *output then there is also taint
// flow from input to output.
this.hasTaintFlow(input.getIndirectionInput(), output.getIndirectionOutput()) and
// No need to add taint flow if we already have data flow.
not this.hasDataFlow(input, output)
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
exists(int i |
input.isParameter(i) and
not this.isLocaleParameter(i) and
// These functions always return the same pointer as they are given
this.hasGlobalOrStdOrBslName([strrev(), strlwr(), strupr()]) and
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
output.isReturnValue()
)
}

View File

@@ -148,119 +148,81 @@ class HashCons extends HCBase {
/** Gets the kind of the HC. This can be useful for debugging. */
string getKind() {
if this instanceof HC_IntLiteral
then result = "IntLiteral"
else
if this instanceof HC_EnumConstantAccess
then result = "EnumConstantAccess"
else
if this instanceof HC_FloatLiteral
then result = "FloatLiteral"
else
if this instanceof HC_StringLiteral
then result = "StringLiteral"
else
if this instanceof HC_Nullptr
then result = "Nullptr"
else
if this instanceof HC_Variable
then result = "Variable"
else
if this instanceof HC_FieldAccess
then result = "FieldAccess"
else
if this instanceof HC_Deref
then result = "Deref"
else
if this instanceof HC_ThisExpr
then result = "ThisExpr"
else
if this instanceof HC_Conversion
then result = "Conversion"
else
if this instanceof HC_BinaryOp
then result = "BinaryOp"
else
if this instanceof HC_UnaryOp
then result = "UnaryOp"
else
if this instanceof HC_ArrayAccess
then result = "ArrayAccess"
else
if this instanceof HC_Unanalyzable
then result = "Unanalyzable"
else
if this instanceof HC_NonmemberFunctionCall
then result = "NonmemberFunctionCall"
else
if this instanceof HC_MemberFunctionCall
then result = "MemberFunctionCall"
else
if this instanceof HC_NewExpr
then result = "NewExpr"
else
if this instanceof HC_NewArrayExpr
then result = "NewArrayExpr"
else
if this instanceof HC_SizeofType
then result = "SizeofTypeOperator"
else
if this instanceof HC_SizeofExpr
then result = "SizeofExprOperator"
else
if this instanceof HC_AlignofType
then result = "AlignofTypeOperator"
else
if this instanceof HC_AlignofExpr
then result = "AlignofExprOperator"
else
if this instanceof HC_UuidofOperator
then result = "UuidofOperator"
else
if this instanceof HC_TypeidType
then result = "TypeidType"
else
if this instanceof HC_TypeidExpr
then result = "TypeidExpr"
else
if this instanceof HC_ArrayAggregateLiteral
then result = "ArrayAggregateLiteral"
else
if this instanceof HC_ClassAggregateLiteral
then result = "ClassAggregateLiteral"
else
if this instanceof HC_DeleteExpr
then result = "DeleteExpr"
else
if this instanceof HC_DeleteArrayExpr
then result = "DeleteArrayExpr"
else
if this instanceof HC_ThrowExpr
then result = "ThrowExpr"
else
if this instanceof HC_ReThrowExpr
then result = "ReThrowExpr"
else
if this instanceof HC_ExprCall
then result = "ExprCall"
else
if
this instanceof
HC_ConditionalExpr
then result = "ConditionalExpr"
else
if
this instanceof
HC_NoExceptExpr
then result = "NoExceptExpr"
else
if
this instanceof
HC_AllocatorArgZero
then
result =
"AllocatorArgZero"
else result = "error"
result = this.getKind0()
or
not exists(this.getKind0()) and result = "error"
}
private string getKind0() {
this instanceof HC_IntLiteral and result = "IntLiteral"
or
this instanceof HC_EnumConstantAccess and result = "EnumConstantAccess"
or
this instanceof HC_FloatLiteral and result = "FloatLiteral"
or
this instanceof HC_StringLiteral and result = "StringLiteral"
or
this instanceof HC_Nullptr and result = "Nullptr"
or
this instanceof HC_Variable and result = "Variable"
or
this instanceof HC_FieldAccess and result = "FieldAccess"
or
this instanceof HC_Deref and result = "Deref"
or
this instanceof HC_ThisExpr and result = "ThisExpr"
or
this instanceof HC_Conversion and result = "Conversion"
or
this instanceof HC_BinaryOp and result = "BinaryOp"
or
this instanceof HC_UnaryOp and result = "UnaryOp"
or
this instanceof HC_ArrayAccess and result = "ArrayAccess"
or
this instanceof HC_Unanalyzable and result = "Unanalyzable"
or
this instanceof HC_NonmemberFunctionCall and result = "NonmemberFunctionCall"
or
this instanceof HC_MemberFunctionCall and result = "MemberFunctionCall"
or
this instanceof HC_NewExpr and result = "NewExpr"
or
this instanceof HC_NewArrayExpr and result = "NewArrayExpr"
or
this instanceof HC_SizeofType and result = "SizeofTypeOperator"
or
this instanceof HC_SizeofExpr and result = "SizeofExprOperator"
or
this instanceof HC_AlignofType and result = "AlignofTypeOperator"
or
this instanceof HC_AlignofExpr and result = "AlignofExprOperator"
or
this instanceof HC_UuidofOperator and result = "UuidofOperator"
or
this instanceof HC_TypeidType and result = "TypeidType"
or
this instanceof HC_TypeidExpr and result = "TypeidExpr"
or
this instanceof HC_ArrayAggregateLiteral and result = "ArrayAggregateLiteral"
or
this instanceof HC_ClassAggregateLiteral and result = "ClassAggregateLiteral"
or
this instanceof HC_DeleteExpr and result = "DeleteExpr"
or
this instanceof HC_DeleteArrayExpr and result = "DeleteArrayExpr"
or
this instanceof HC_ThrowExpr and result = "ThrowExpr"
or
this instanceof HC_ReThrowExpr and result = "ReThrowExpr"
or
this instanceof HC_ExprCall and result = "ExprCall"
or
this instanceof HC_ConditionalExpr and result = "ConditionalExpr"
or
this instanceof HC_NoExceptExpr and result = "NoExceptExpr"
or
this instanceof HC_AllocatorArgZero and result = "AllocatorArgZero"
}
/**

View File

@@ -776,7 +776,7 @@ case @usertype.kind of
| 2 = @class
| 3 = @union
| 4 = @enum
| 5 = @typedef // classic C: typedef typedef type name
// ... 5 = @typedef deprecated // classic C: typedef typedef type name
// ... 6 = @template deprecated
| 7 = @template_parameter
| 8 = @template_template_parameter
@@ -785,10 +785,11 @@ case @usertype.kind of
// ... 11 objc_protocol deprecated
// ... 12 objc_category deprecated
| 13 = @scoped_enum
| 14 = @using_alias // a using name = type style typedef
// ... 14 = @using_alias deprecated // a using name = type style typedef
| 15 = @template_struct
| 16 = @template_class
| 17 = @template_union
| 18 = @alias
;
*/
@@ -811,6 +812,17 @@ usertype_uuid(
string uuid: string ref
);
/*
case @usertype.alias_kind of
| 0 = @typedef
| 1 = @alias
*/
usertype_alias_kind(
int id: @usertype ref,
int alias_kind: int ref
)
nontype_template_parameters(
int id: @expr ref
);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
description: Mix typedefs and usings
compatibility: full
usertypes.rel: run usertypes.qlo
usertype_alias_kind.rel: run usertype_alias_kind.qlo

View File

@@ -0,0 +1,14 @@
class UserType extends @usertype {
string toString() { none() }
}
bindingset[kind]
int getKind(int kind) {
kind = 5 and result = 0
or
kind = 14 and result = 1
}
from UserType usertype, int kind
where usertypes(usertype, _, kind)
select usertype, getKind(kind)

View File

@@ -0,0 +1,10 @@
class UserType extends @usertype {
string toString() { none() }
}
bindingset[kind]
int getKind(int kind) { if kind = [5, 14] then result = 18 else result = kind }
from UserType usertype, string name, int kind
where usertypes(usertype, name, kind)
select usertype, name, getKind(kind)

View File

@@ -33,8 +33,9 @@ predicate allocSink(HeuristicAllocationExpr alloc, DataFlow::Node sink) {
)
}
predicate readsVariable(LoadInstruction load, Variable var) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
predicate readsVariable(LoadInstruction load, Variable var, IRBlock bb) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var and
bb = load.getBlock()
}
predicate hasUpperBoundsCheck(Variable var) {
@@ -46,10 +47,18 @@ predicate hasUpperBoundsCheck(Variable var) {
)
}
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
exists(Instruction instr | instr = node.asOperand().getDef() |
readsVariable(instr, checkedVar) and
any(IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
predicate variableEqualityCheckedInBlock(Variable checkedVar, IRBlock bb) {
exists(Operand access |
readsVariable(access.getDef(), checkedVar, _) and
any(IRGuardCondition guard).ensuresEq(access, _, _, bb, true)
)
}
predicate nodeIsBarrierEquality(DataFlow::Node node) {
exists(Variable checkedVar, Instruction instr, IRBlock bb |
instr = node.asOperand().getDef() and
readsVariable(instr, checkedVar, bb) and
variableEqualityCheckedInBlock(checkedVar, bb)
)
}
@@ -72,14 +81,11 @@ module TaintedAllocationSizeConfig implements DataFlow::ConfigSig {
)
or
exists(Variable checkedVar, Instruction instr | instr = node.asOperand().getDef() |
readsVariable(instr, checkedVar) and
readsVariable(instr, checkedVar, _) and
hasUpperBoundsCheck(checkedVar)
)
or
exists(Variable checkedVar, Operand access |
readsVariable(access.getDef(), checkedVar) and
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
)
nodeIsBarrierEquality(node)
or
// block flow to inside of identified allocation functions (this flow leads
// to duplicate results)

View File

@@ -14,48 +14,6 @@ import cpp
import semmle.code.cpp.dataflow.new.DataFlow
import Flow::PathGraph
/**
* Holds if `f` is a field located at byte offset `offset` in `c`.
*
* Note that predicate is recursive, so that given the following:
* ```cpp
* struct S1 {
* int a;
* void* b;
* };
*
* struct S2 {
* S1 s1;
* char c;
* };
* ```
* both `hasAFieldWithOffset(S2, s1, 0)` and `hasAFieldWithOffset(S2, a, 0)`
* holds.
*/
predicate hasAFieldWithOffset(Class c, Field f, int offset) {
// Base case: `f` is a field in `c`.
f = c.getAField() and
offset = f.getByteOffset() and
not f.getUnspecifiedType().(Class).hasDefinition()
or
// Otherwise, we find the struct that is a field of `c` which then has
// the field `f` as a member.
exists(Field g |
g = c.getAField() and
// Find the field with the largest offset that's less than or equal to
// offset. That's the struct we need to search recursively.
g =
max(Field cand, int candOffset |
cand = c.getAField() and
candOffset = cand.getByteOffset() and
offset >= candOffset
|
cand order by candOffset
) and
hasAFieldWithOffset(g.getUnspecifiedType(), f, offset - g.getByteOffset())
)
}
/** Holds if `f` is the last field of its declaring class. */
predicate lastField(Field f) {
exists(Class c | c = f.getDeclaringType() |
@@ -75,7 +33,7 @@ predicate lastField(Field f) {
bindingset[f1, offset, c2]
pragma[inline_late]
predicate hasCompatibleFieldAtOffset(Field f1, int offset, Class c2) {
exists(Field f2 | hasAFieldWithOffset(c2, f2, offset) |
exists(Field f2 | offset = f2.getOffsetInClass(c2) |
// Let's not deal with bit-fields for now.
f2 instanceof BitField
or
@@ -100,7 +58,7 @@ predicate prefix(Class c1, Class c2) {
exists(Field f1, int offset |
// Let's not deal with bit-fields for now.
not f1 instanceof BitField and
hasAFieldWithOffset(c1, f1, offset)
offset = f1.getOffsetInClass(c1)
|
hasCompatibleFieldAtOffset(f1, offset, c2)
)
@@ -108,7 +66,7 @@ predicate prefix(Class c1, Class c2) {
forall(Field f1, int offset |
// Let's not deal with bit-fields for now.
not f1 instanceof BitField and
hasAFieldWithOffset(c1, f1, offset)
offset = f1.getOffsetInClass(c1)
|
hasCompatibleFieldAtOffset(f1, offset, c2)
)

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The "Call to memory access function may overflow buffer" query (`cpp/overflow-buffer`) now produces fewer FPs involving non-static member variables.

View File

@@ -77,3 +77,18 @@
| test.cpp:193:8:193:9 | b1 |
| test.cpp:193:8:193:15 | ... \|\| ... |
| test.cpp:193:14:193:15 | b2 |
| test.cpp:211:9:211:15 | ... == ... |
| test.cpp:214:9:214:17 | ... == ... |
| test.cpp:217:9:217:15 | ... == ... |
| test.cpp:220:9:220:14 | ... == ... |
| test.cpp:223:9:223:16 | ... == ... |
| test.cpp:226:9:226:14 | ... == ... |
| test.cpp:229:9:229:14 | ... == ... |
| test.cpp:232:9:232:18 | ... == ... |
| test.cpp:235:9:235:17 | ... == ... |
| test.cpp:238:9:238:17 | ... == ... |
| test.cpp:241:9:241:17 | ... == ... |
| test.cpp:241:9:241:30 | ... && ... |
| test.cpp:241:9:241:43 | ... && ... |
| test.cpp:241:22:241:30 | ... == ... |
| test.cpp:241:35:241:43 | ... == ... |

View File

@@ -653,3 +653,116 @@
| 206 | c != 0 when c is true |
| 206 | c == 0 when ! ... is true |
| 206 | c == 0 when c is false |
| 211 | 0 != sc+0 when ... == ... is false |
| 211 | 0 == sc+0 when ... == ... is true |
| 211 | ... == ... != 0 when ... == ... is true |
| 211 | ... == ... != 1 when ... == ... is false |
| 211 | ... == ... == 0 when ... == ... is false |
| 211 | ... == ... == 1 when ... == ... is true |
| 211 | sc != 0 when ... == ... is false |
| 211 | sc != 0+0 when ... == ... is false |
| 211 | sc == 0 when ... == ... is true |
| 211 | sc == 0+0 when ... == ... is true |
| 214 | 0 != sc+0 when ... == ... is false |
| 214 | 0 == sc+0 when ... == ... is true |
| 214 | ... == ... != 0 when ... == ... is true |
| 214 | ... == ... != 1 when ... == ... is false |
| 214 | ... == ... == 0 when ... == ... is false |
| 214 | ... == ... == 1 when ... == ... is true |
| 214 | sc != 0 when ... == ... is false |
| 214 | sc != 0+0 when ... == ... is false |
| 214 | sc == 0 when ... == ... is true |
| 214 | sc == 0+0 when ... == ... is true |
| 217 | 0 != ul+0 when ... == ... is false |
| 217 | 0 == ul+0 when ... == ... is true |
| 217 | ... == ... != 0 when ... == ... is true |
| 217 | ... == ... != 1 when ... == ... is false |
| 217 | ... == ... == 0 when ... == ... is false |
| 217 | ... == ... == 1 when ... == ... is true |
| 217 | ul != 0 when ... == ... is false |
| 217 | ul != 0+0 when ... == ... is false |
| 217 | ul == 0 when ... == ... is true |
| 217 | ul == 0+0 when ... == ... is true |
| 220 | 0 != f+0 when ... == ... is false |
| 220 | 0 == f+0 when ... == ... is true |
| 220 | ... == ... != 0 when ... == ... is true |
| 220 | ... == ... != 1 when ... == ... is false |
| 220 | ... == ... == 0 when ... == ... is false |
| 220 | ... == ... == 1 when ... == ... is true |
| 220 | f != 0+0 when ... == ... is false |
| 220 | f == 0+0 when ... == ... is true |
| 223 | 0.0 != f+0 when ... == ... is false |
| 223 | 0.0 == f+0 when ... == ... is true |
| 223 | ... == ... != 0 when ... == ... is true |
| 223 | ... == ... != 1 when ... == ... is false |
| 223 | ... == ... == 0 when ... == ... is false |
| 223 | ... == ... == 1 when ... == ... is true |
| 223 | f != 0.0+0 when ... == ... is false |
| 223 | f == 0.0+0 when ... == ... is true |
| 226 | 0 != d+0 when ... == ... is false |
| 226 | 0 == d+0 when ... == ... is true |
| 226 | ... == ... != 0 when ... == ... is true |
| 226 | ... == ... != 1 when ... == ... is false |
| 226 | ... == ... == 0 when ... == ... is false |
| 226 | ... == ... == 1 when ... == ... is true |
| 226 | d != 0+0 when ... == ... is false |
| 226 | d == 0+0 when ... == ... is true |
| 229 | 0 != b+0 when ... == ... is false |
| 229 | 0 == b+0 when ... == ... is true |
| 229 | ... == ... != 0 when ... == ... is true |
| 229 | ... == ... != 1 when ... == ... is false |
| 229 | ... == ... == 0 when ... == ... is false |
| 229 | ... == ... == 1 when ... == ... is true |
| 229 | b != 0 when ... == ... is false |
| 229 | b != 0+0 when ... == ... is false |
| 229 | b == 0 when ... == ... is true |
| 229 | b == 0+0 when ... == ... is true |
| 232 | 0 != b+0 when ... == ... is false |
| 232 | 0 == b+0 when ... == ... is true |
| 232 | ... == ... != 0 when ... == ... is true |
| 232 | ... == ... != 1 when ... == ... is false |
| 232 | ... == ... == 0 when ... == ... is false |
| 232 | ... == ... == 1 when ... == ... is true |
| 232 | b != 0 when ... == ... is false |
| 232 | b != 0+0 when ... == ... is false |
| 232 | b == 0 when ... == ... is true |
| 232 | b == 0+0 when ... == ... is true |
| 235 | 0 != i+0 when ... == ... is false |
| 235 | 0 == i+0 when ... == ... is true |
| 235 | ... == ... != 0 when ... == ... is true |
| 235 | ... == ... != 1 when ... == ... is false |
| 235 | ... == ... == 0 when ... == ... is false |
| 235 | ... == ... == 1 when ... == ... is true |
| 235 | i != 0 when ... == ... is false |
| 235 | i != 0+0 when ... == ... is false |
| 235 | i == 0 when ... == ... is true |
| 235 | i == 0+0 when ... == ... is true |
| 238 | 0 != f+0 when ... == ... is false |
| 238 | 0 == f+0 when ... == ... is true |
| 238 | ... == ... != 0 when ... == ... is true |
| 238 | ... == ... != 1 when ... == ... is false |
| 238 | ... == ... == 0 when ... == ... is false |
| 238 | ... == ... == 1 when ... == ... is true |
| 238 | f != 0+0 when ... == ... is false |
| 238 | f == 0+0 when ... == ... is true |
| 241 | 0 != f+0 when ... == ... is false |
| 241 | 0 != i+0 when ... == ... is false |
| 241 | 0 == f+0 when ... && ... is true |
| 241 | 0 == f+0 when ... == ... is true |
| 241 | 0 == i+0 when ... && ... is true |
| 241 | 0 == i+0 when ... == ... is true |
| 241 | ... == ... != 0 when ... && ... is true |
| 241 | ... == ... != 0 when ... == ... is true |
| 241 | ... == ... != 1 when ... == ... is false |
| 241 | ... == ... == 0 when ... == ... is false |
| 241 | ... == ... == 1 when ... && ... is true |
| 241 | ... == ... == 1 when ... == ... is true |
| 241 | f != 0+0 when ... == ... is false |
| 241 | f == 0+0 when ... && ... is true |
| 241 | f == 0+0 when ... == ... is true |
| 241 | i != 0 when ... == ... is false |
| 241 | i != 0+0 when ... == ... is false |
| 241 | i == 0 when ... && ... is true |
| 241 | i == 0 when ... == ... is true |
| 241 | i == 0+0 when ... && ... is true |
| 241 | i == 0+0 when ... == ... is true |

View File

@@ -146,3 +146,21 @@
| test.cpp:193:8:193:15 | ... \|\| ... | false | 193 | 196 |
| test.cpp:193:8:193:15 | ... \|\| ... | true | 197 | 199 |
| test.cpp:193:14:193:15 | b2 | false | 192 | 193 |
| test.cpp:211:9:211:15 | ... == ... | true | 211 | 212 |
| test.cpp:214:9:214:17 | ... == ... | true | 214 | 215 |
| test.cpp:217:9:217:15 | ... == ... | true | 217 | 218 |
| test.cpp:220:9:220:14 | ... == ... | true | 220 | 221 |
| test.cpp:223:9:223:16 | ... == ... | true | 223 | 224 |
| test.cpp:226:9:226:14 | ... == ... | true | 226 | 227 |
| test.cpp:229:9:229:14 | ... == ... | true | 229 | 230 |
| test.cpp:232:9:232:18 | ... == ... | true | 232 | 233 |
| test.cpp:235:9:235:17 | ... == ... | true | 235 | 236 |
| test.cpp:238:9:238:17 | ... == ... | true | 238 | 239 |
| test.cpp:241:9:241:17 | ... == ... | true | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | true | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | true | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | true | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | true | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | true | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | true | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | true | 241 | 242 |

View File

@@ -207,6 +207,96 @@ binary
| test.cpp:176:7:176:8 | ! ... | test.cpp:174:16:174:16 | b | >= | test.cpp:174:12:174:12 | a | 0 | 176 | 178 |
| test.cpp:176:8:176:8 | c | test.cpp:174:12:174:12 | a | < | test.cpp:174:16:174:16 | b | 1 | 176 | 178 |
| test.cpp:176:8:176:8 | c | test.cpp:174:16:174:16 | b | >= | test.cpp:174:12:174:12 | a | 0 | 176 | 178 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:211:9:211:10 | sc | == | test.cpp:211:15:211:15 | 0 | 0 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:211:15:211:15 | 0 | == | test.cpp:211:9:211:10 | sc | 0 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:214:9:214:10 | sc | == | test.cpp:214:15:214:17 | 0 | 0 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:214:15:214:17 | 0 | == | test.cpp:214:9:214:10 | sc | 0 | 211 | 212 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:211:9:211:10 | sc | == | test.cpp:211:15:211:15 | 0 | 0 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:211:15:211:15 | 0 | == | test.cpp:211:9:211:10 | sc | 0 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:214:9:214:10 | sc | == | test.cpp:214:15:214:17 | 0 | 0 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:214:15:214:17 | 0 | == | test.cpp:214:9:214:10 | sc | 0 | 214 | 215 |
| test.cpp:217:9:217:15 | ... == ... | test.cpp:217:9:217:10 | ul | == | test.cpp:217:15:217:15 | 0 | 0 | 217 | 218 |
| test.cpp:217:9:217:15 | ... == ... | test.cpp:217:15:217:15 | 0 | == | test.cpp:217:9:217:10 | ul | 0 | 217 | 218 |
| test.cpp:220:9:220:14 | ... == ... | test.cpp:220:9:220:9 | f | == | test.cpp:220:14:220:14 | 0 | 0 | 220 | 221 |
| test.cpp:220:9:220:14 | ... == ... | test.cpp:220:14:220:14 | 0 | == | test.cpp:220:9:220:9 | f | 0 | 220 | 221 |
| test.cpp:223:9:223:16 | ... == ... | test.cpp:223:9:223:9 | f | == | test.cpp:223:14:223:16 | 0.0 | 0 | 223 | 224 |
| test.cpp:223:9:223:16 | ... == ... | test.cpp:223:14:223:16 | 0.0 | == | test.cpp:223:9:223:9 | f | 0 | 223 | 224 |
| test.cpp:226:9:226:14 | ... == ... | test.cpp:226:9:226:9 | d | == | test.cpp:226:14:226:14 | 0 | 0 | 226 | 227 |
| test.cpp:226:9:226:14 | ... == ... | test.cpp:226:14:226:14 | 0 | == | test.cpp:226:9:226:9 | d | 0 | 226 | 227 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:229:9:229:9 | b | == | test.cpp:229:14:229:14 | 0 | 0 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:229:14:229:14 | 0 | == | test.cpp:229:9:229:9 | b | 0 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:232:9:232:9 | b | == | test.cpp:232:14:232:18 | 0 | 0 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:232:14:232:18 | 0 | == | test.cpp:232:9:232:9 | b | 0 | 229 | 230 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:229:9:229:9 | b | == | test.cpp:229:14:229:14 | 0 | 0 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:229:14:229:14 | 0 | == | test.cpp:229:9:229:9 | b | 0 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:232:9:232:9 | b | == | test.cpp:232:14:232:18 | 0 | 0 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:232:14:232:18 | 0 | == | test.cpp:232:9:232:9 | b | 0 | 232 | 233 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:235:12:235:12 | i | == | test.cpp:235:17:235:17 | 0 | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:235:17:235:17 | 0 | == | test.cpp:235:12:235:12 | i | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:12:241:12 | i | == | test.cpp:241:17:241:17 | 0 | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:17:241:17 | 0 | == | test.cpp:241:12:241:12 | i | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:38:241:38 | i | == | test.cpp:241:43:241:43 | 0 | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:43:241:43 | 0 | == | test.cpp:241:38:241:38 | i | 0 | 235 | 236 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:238:12:238:12 | f | == | test.cpp:238:17:238:17 | 0 | 0 | 238 | 239 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:238:17:238:17 | 0 | == | test.cpp:238:12:238:12 | f | 0 | 238 | 239 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:241:25:241:25 | f | == | test.cpp:241:30:241:30 | 0 | 0 | 238 | 239 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:241:30:241:30 | 0 | == | test.cpp:241:25:241:25 | f | 0 | 238 | 239 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:12:235:12 | i | == | test.cpp:235:17:235:17 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:12:235:12 | i | == | test.cpp:235:17:235:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:17:235:17 | 0 | == | test.cpp:235:12:235:12 | i | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:17:235:17 | 0 | == | test.cpp:235:12:235:12 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:12:241:12 | i | == | test.cpp:241:17:241:17 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:12:241:12 | i | == | test.cpp:241:17:241:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:17:241:17 | 0 | == | test.cpp:241:12:241:12 | i | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:17:241:17 | 0 | == | test.cpp:241:12:241:12 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:38:241:38 | i | == | test.cpp:241:43:241:43 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:38:241:38 | i | == | test.cpp:241:43:241:43 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:43:241:43 | 0 | == | test.cpp:241:38:241:38 | i | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:43:241:43 | 0 | == | test.cpp:241:38:241:38 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:12:235:12 | i | == | test.cpp:235:17:235:17 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:12:235:12 | i | == | test.cpp:235:17:235:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:17:235:17 | 0 | == | test.cpp:235:12:235:12 | i | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:17:235:17 | 0 | == | test.cpp:235:12:235:12 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:12:238:12 | f | == | test.cpp:238:17:238:17 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:12:238:12 | f | == | test.cpp:238:17:238:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:17:238:17 | 0 | == | test.cpp:238:12:238:12 | f | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:17:238:17 | 0 | == | test.cpp:238:12:238:12 | f | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:12:241:12 | i | == | test.cpp:241:17:241:17 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:12:241:12 | i | == | test.cpp:241:17:241:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:17:241:17 | 0 | == | test.cpp:241:12:241:12 | i | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:17:241:17 | 0 | == | test.cpp:241:12:241:12 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:25:241:25 | f | == | test.cpp:241:30:241:30 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:25:241:25 | f | == | test.cpp:241:30:241:30 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:30:241:30 | 0 | == | test.cpp:241:25:241:25 | f | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:30:241:30 | 0 | == | test.cpp:241:25:241:25 | f | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:38:241:38 | i | == | test.cpp:241:43:241:43 | 0 | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:38:241:38 | i | == | test.cpp:241:43:241:43 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:43:241:43 | 0 | == | test.cpp:241:38:241:38 | i | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:43:241:43 | 0 | == | test.cpp:241:38:241:38 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:235:12:235:12 | i | == | test.cpp:235:17:235:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:235:17:235:17 | 0 | == | test.cpp:235:12:235:12 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:238:12:238:12 | f | == | test.cpp:238:17:238:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:238:17:238:17 | 0 | == | test.cpp:238:12:238:12 | f | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:12:241:12 | i | == | test.cpp:241:17:241:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:17:241:17 | 0 | == | test.cpp:241:12:241:12 | i | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:25:241:25 | f | == | test.cpp:241:30:241:30 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:30:241:30 | 0 | == | test.cpp:241:25:241:25 | f | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:38:241:38 | i | == | test.cpp:241:43:241:43 | 0 | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:43:241:43 | 0 | == | test.cpp:241:38:241:38 | i | 0 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:12:238:12 | f | == | test.cpp:238:17:238:17 | 0 | 0 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:12:238:12 | f | == | test.cpp:238:17:238:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:17:238:17 | 0 | == | test.cpp:238:12:238:12 | f | 0 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:17:238:17 | 0 | == | test.cpp:238:12:238:12 | f | 0 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:25:241:25 | f | == | test.cpp:241:30:241:30 | 0 | 0 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:25:241:25 | f | == | test.cpp:241:30:241:30 | 0 | 0 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:30:241:30 | 0 | == | test.cpp:241:25:241:25 | f | 0 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:30:241:30 | 0 | == | test.cpp:241:25:241:25 | f | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:235:12:235:12 | i | == | test.cpp:235:17:235:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:235:17:235:17 | 0 | == | test.cpp:235:12:235:12 | i | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:12:241:12 | i | == | test.cpp:241:17:241:17 | 0 | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:17:241:17 | 0 | == | test.cpp:241:12:241:12 | i | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:38:241:38 | i | == | test.cpp:241:43:241:43 | 0 | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:43:241:43 | 0 | == | test.cpp:241:38:241:38 | i | 0 | 241 | 242 |
unary
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | 1 | 10 | 11 |
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | 1 | 7 | 9 |
@@ -712,3 +802,123 @@ unary
| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | == | 0 | 193 | 196 |
| test.cpp:193:14:193:15 | b2 | test.cpp:193:14:193:15 | b2 | != | 1 | 192 | 193 |
| test.cpp:193:14:193:15 | b2 | test.cpp:193:14:193:15 | b2 | == | 0 | 192 | 193 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:211:9:211:10 | sc | == | 0 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:211:9:211:15 | ... == ... | != | 0 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:211:9:211:15 | ... == ... | == | 1 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:214:9:214:10 | sc | == | 0 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:214:9:214:17 | ... == ... | != | 0 | 211 | 212 |
| test.cpp:211:9:211:15 | ... == ... | test.cpp:214:9:214:17 | ... == ... | == | 1 | 211 | 212 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:211:9:211:10 | sc | == | 0 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:211:9:211:15 | ... == ... | != | 0 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:211:9:211:15 | ... == ... | == | 1 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:214:9:214:10 | sc | == | 0 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:214:9:214:17 | ... == ... | != | 0 | 214 | 215 |
| test.cpp:214:9:214:17 | ... == ... | test.cpp:214:9:214:17 | ... == ... | == | 1 | 214 | 215 |
| test.cpp:217:9:217:15 | ... == ... | test.cpp:217:9:217:10 | ul | == | 0 | 217 | 218 |
| test.cpp:217:9:217:15 | ... == ... | test.cpp:217:9:217:15 | ... == ... | != | 0 | 217 | 218 |
| test.cpp:217:9:217:15 | ... == ... | test.cpp:217:9:217:15 | ... == ... | == | 1 | 217 | 218 |
| test.cpp:220:9:220:14 | ... == ... | test.cpp:220:9:220:14 | ... == ... | != | 0 | 220 | 221 |
| test.cpp:220:9:220:14 | ... == ... | test.cpp:220:9:220:14 | ... == ... | == | 1 | 220 | 221 |
| test.cpp:223:9:223:16 | ... == ... | test.cpp:223:9:223:16 | ... == ... | != | 0 | 223 | 224 |
| test.cpp:223:9:223:16 | ... == ... | test.cpp:223:9:223:16 | ... == ... | == | 1 | 223 | 224 |
| test.cpp:226:9:226:14 | ... == ... | test.cpp:226:9:226:14 | ... == ... | != | 0 | 226 | 227 |
| test.cpp:226:9:226:14 | ... == ... | test.cpp:226:9:226:14 | ... == ... | == | 1 | 226 | 227 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:229:9:229:9 | b | == | 0 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:229:9:229:14 | ... == ... | != | 0 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:229:9:229:14 | ... == ... | == | 1 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:232:9:232:9 | b | == | 0 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:232:9:232:18 | ... == ... | != | 0 | 229 | 230 |
| test.cpp:229:9:229:14 | ... == ... | test.cpp:232:9:232:18 | ... == ... | == | 1 | 229 | 230 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:229:9:229:9 | b | == | 0 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:229:9:229:14 | ... == ... | != | 0 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:229:9:229:14 | ... == ... | == | 1 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:232:9:232:9 | b | == | 0 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:232:9:232:18 | ... == ... | != | 0 | 232 | 233 |
| test.cpp:232:9:232:18 | ... == ... | test.cpp:232:9:232:18 | ... == ... | == | 1 | 232 | 233 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:235:9:235:17 | ... == ... | != | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:235:9:235:17 | ... == ... | == | 1 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:235:12:235:12 | i | == | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:9:241:17 | ... == ... | != | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:9:241:17 | ... == ... | == | 1 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:12:241:12 | i | == | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:35:241:43 | ... == ... | != | 0 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:35:241:43 | ... == ... | == | 1 | 235 | 236 |
| test.cpp:235:9:235:17 | ... == ... | test.cpp:241:38:241:38 | i | == | 0 | 235 | 236 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:238:9:238:17 | ... == ... | != | 0 | 238 | 239 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:238:9:238:17 | ... == ... | == | 1 | 238 | 239 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:241:22:241:30 | ... == ... | != | 0 | 238 | 239 |
| test.cpp:238:9:238:17 | ... == ... | test.cpp:241:22:241:30 | ... == ... | == | 1 | 238 | 239 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:9:235:17 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:9:235:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:9:235:17 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:9:235:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:12:235:12 | i | == | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:235:12:235:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:9:241:17 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:9:241:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:9:241:17 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:9:241:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:12:241:12 | i | == | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:12:241:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:35:241:43 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:35:241:43 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:35:241:43 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:35:241:43 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:38:241:38 | i | == | 0 | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | test.cpp:241:38:241:38 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:9:235:17 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:9:235:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:9:235:17 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:9:235:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:12:235:12 | i | == | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:235:12:235:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:9:238:17 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:9:238:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:9:238:17 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:238:9:238:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:9:241:17 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:9:241:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:9:241:17 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:9:241:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:12:241:12 | i | == | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:12:241:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:22:241:30 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:22:241:30 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:22:241:30 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:22:241:30 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:35:241:43 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:35:241:43 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:35:241:43 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:35:241:43 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:38:241:38 | i | == | 0 | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | test.cpp:241:38:241:38 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:235:9:235:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:235:9:235:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:235:12:235:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:238:9:238:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:238:9:238:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:9:241:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:9:241:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:12:241:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:22:241:30 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:22:241:30 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:35:241:43 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:35:241:43 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | test.cpp:241:38:241:38 | i | == | 0 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:9:238:17 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:9:238:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:9:238:17 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:238:9:238:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:22:241:30 | ... == ... | != | 0 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:22:241:30 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:22:241:30 | ... == ... | == | 1 | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | test.cpp:241:22:241:30 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:235:9:235:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:235:9:235:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:235:12:235:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:9:241:17 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:9:241:17 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:12:241:12 | i | == | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:35:241:43 | ... == ... | != | 0 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:35:241:43 | ... == ... | == | 1 | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | test.cpp:241:38:241:38 | i | == | 0 | 241 | 242 |

View File

@@ -198,4 +198,47 @@ void test_logical_or(bool b1, bool b2) {
use(b1);
use(b2);
}
}
}
struct Mystruct {
int i;
float f;
};
int test_types(signed char sc, unsigned long ul, float f, double d, bool b, Mystruct &ms) {
int ctr = 0;
if (sc == 0) {
ctr++;
}
if (sc == 0x0) {
ctr++;
}
if (ul == 0) {
ctr++;
}
if (f == 0) {
ctr++;
}
if (f == 0.0) {
ctr++;
}
if (d == 0) {
ctr++;
}
if (b == 0) {
ctr++;
}
if (b == false) {
ctr++;
}
if (ms.i == 0) {
ctr++;
}
if (ms.f == 0) {
ctr++;
}
if (ms.i == 0 && ms.f == 0 && ms.i == 0) {
ctr++;
}
}

View File

@@ -102,32 +102,49 @@ sourceCallables
| tests.cpp:139:6:139:10 | value |
| tests.cpp:140:6:140:11 | value2 |
| tests.cpp:141:7:141:9 | ptr |
| tests.cpp:144:5:144:19 | madArg0ToReturn |
| tests.cpp:144:25:144:25 | x |
| tests.cpp:145:6:145:28 | madArg0ToReturnIndirect |
| tests.cpp:145:34:145:34 | x |
| tests.cpp:146:5:146:15 | notASummary |
| tests.cpp:146:21:146:21 | x |
| tests.cpp:147:5:147:28 | madArg0ToReturnValueFlow |
| tests.cpp:147:34:147:34 | x |
| tests.cpp:148:5:148:27 | madArg0IndirectToReturn |
| tests.cpp:148:34:148:34 | x |
| tests.cpp:149:5:149:33 | madArg0DoubleIndirectToReturn |
| tests.cpp:149:41:149:41 | x |
| tests.cpp:150:5:150:30 | madArg0NotIndirectToReturn |
| tests.cpp:150:37:150:37 | x |
| tests.cpp:151:6:151:26 | madArg0ToArg1Indirect |
| tests.cpp:151:32:151:32 | x |
| tests.cpp:151:40:151:40 | y |
| tests.cpp:152:6:152:34 | madArg0IndirectToArg1Indirect |
| tests.cpp:152:47:152:47 | x |
| tests.cpp:152:55:152:55 | y |
| tests.cpp:153:5:153:18 | madArgsComplex |
| tests.cpp:153:25:153:25 | a |
| tests.cpp:153:33:153:33 | b |
| tests.cpp:153:40:153:40 | c |
| tests.cpp:153:47:153:47 | d |
| tests.cpp:154:5:154:14 | madArgsAny |
| tests.cpp:154:20:154:20 | a |
| tests.cpp:154:28:154:28 | b |
| tests.cpp:155:5:155:28 | madAndImplementedComplex |
| tests.cpp:155:34:155:34 | a |
| tests.cpp:155:41:155:41 | b |
| tests.cpp:155:48:155:48 | c |
| tests.cpp:160:5:160:24 | madArg0FieldToReturn |
| tests.cpp:160:38:160:39 | mc |
| tests.cpp:161:5:161:32 | madArg0IndirectFieldToReturn |
| tests.cpp:161:47:161:48 | mc |
| tests.cpp:162:5:162:32 | madArg0FieldIndirectToReturn |
| tests.cpp:162:46:162:47 | mc |
| tests.cpp:163:13:163:32 | madArg0ToReturnField |
| tests.cpp:163:38:163:38 | x |
| tests.cpp:164:14:164:41 | madArg0ToReturnIndirectField |
| tests.cpp:164:47:164:47 | x |
| tests.cpp:165:13:165:40 | madArg0ToReturnFieldIndirect |
| tests.cpp:165:46:165:46 | x |
| tests.cpp:167:13:167:30 | madFieldToFieldVar |
| tests.cpp:168:13:168:38 | madFieldToIndirectFieldVar |
@@ -160,9 +177,13 @@ sourceCallables
| tests.cpp:280:7:280:23 | qualifierArg0Sink |
| tests.cpp:280:29:280:29 | x |
| tests.cpp:281:7:281:24 | qualifierFieldSink |
| tests.cpp:284:7:284:19 | madArg0ToSelf |
| tests.cpp:284:25:284:25 | x |
| tests.cpp:285:6:285:20 | madSelfToReturn |
| tests.cpp:286:6:286:16 | notASummary |
| tests.cpp:287:7:287:20 | madArg0ToField |
| tests.cpp:287:26:287:26 | x |
| tests.cpp:288:6:288:21 | madFieldToReturn |
| tests.cpp:290:6:290:8 | val |
| tests.cpp:293:7:293:7 | MyDerivedClass |
| tests.cpp:293:7:293:7 | operator= |
@@ -183,6 +204,7 @@ sourceCallables
| tests.cpp:308:52:308:52 | x |
| tests.cpp:309:7:309:31 | namespaceMemberMadSinkVar |
| tests.cpp:310:14:310:44 | namespaceStaticMemberMadSinkVar |
| tests.cpp:313:7:313:30 | namespaceMadSelfToReturn |
| tests.cpp:317:22:317:28 | source3 |
| tests.cpp:319:6:319:23 | test_class_members |
| tests.cpp:320:10:320:11 | mc |
@@ -208,10 +230,14 @@ sourceCallables
| tests.cpp:429:8:429:14 | intPair |
| tests.cpp:430:6:430:10 | first |
| tests.cpp:431:6:431:11 | second |
| tests.cpp:434:5:434:29 | madCallArg0ReturnToReturn |
| tests.cpp:434:37:434:43 | fun_ptr |
| tests.cpp:435:9:435:38 | madCallArg0ReturnToReturnFirst |
| tests.cpp:435:46:435:52 | fun_ptr |
| tests.cpp:436:6:436:25 | madCallArg0WithValue |
| tests.cpp:436:34:436:40 | fun_ptr |
| tests.cpp:436:53:436:57 | value |
| tests.cpp:437:5:437:36 | madCallReturnValueIgnoreFunction |
| tests.cpp:437:45:437:51 | fun_ptr |
| tests.cpp:437:64:437:68 | value |
| tests.cpp:439:5:439:14 | getTainted |
@@ -225,6 +251,7 @@ sourceCallables
| tests.cpp:457:8:457:35 | StructWithTypedefInParameter<int> |
| tests.cpp:458:12:458:15 | Type |
| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
| tests.cpp:459:45:459:45 | x |
| tests.cpp:459:45:459:45 | x |
| tests.cpp:462:6:462:37 | test_parameter_ref_to_return_ref |
@@ -232,6 +259,7 @@ sourceCallables
| tests.cpp:464:36:464:36 | s |
| tests.cpp:465:6:465:6 | y |
| tests.cpp:469:7:469:9 | INT |
| tests.cpp:471:5:471:17 | receive_array |
| tests.cpp:471:23:471:23 | a |
| tests.cpp:473:6:473:23 | test_receive_array |
| tests.cpp:474:6:474:6 | x |

View File

@@ -0,0 +1,30 @@
uniqueEnclosingCallable
uniqueCallEnclosingCallable
uniqueType
uniqueNodeLocation
missingLocation
uniqueNodeToString
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes
postIsNotPre
postHasUniquePre
uniquePostUpdate
postIsInSameCallable
reverseRead
argHasPostUpdate
postWithInFlow
| tests.cpp:436:6:436:25 | [summary] to write: Argument[1] in madCallArg0WithValue | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition
uniqueContentApprox
identityLocalStep
missingArgumentCall
multipleArgumentCall
lambdaCallEnclosingCallableMismatch
speculativeStepAlreadyHasModel

View File

@@ -0,0 +1,2 @@
import testModels
import semmle.code.cpp.ir.dataflow.internal.DataFlowImplConsistency::Consistency

View File

@@ -205,7 +205,7 @@ void test_summaries() {
sink(madAndImplementedComplex(0, 0, 0));
sink(madAndImplementedComplex(source(), 0, 0));
sink(madAndImplementedComplex(0, source(), 0)); // $ ir
sink(madAndImplementedComplex(0, source(), 0)); // Clean. We have a MaD model specifying different behavior.
sink(madAndImplementedComplex(0, 0, source())); // $ ir
sink(madArgsAny(0, 0));

View File

@@ -7741,6 +7741,32 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
| taint.cpp:809:8:809:9 | p2 | taint.cpp:809:7:809:9 | * ... | TAINT |
| taint.cpp:811:12:811:28 | call to SysAllocStringLen | taint.cpp:812:8:812:9 | p3 | |
| taint.cpp:812:8:812:9 | p3 | taint.cpp:812:7:812:9 | * ... | TAINT |
| taint.cpp:817:42:817:46 | p_out | taint.cpp:817:42:817:46 | p_out | |
| taint.cpp:817:42:817:46 | p_out | taint.cpp:819:4:819:8 | p_out | |
| taint.cpp:817:62:817:65 | p_in | taint.cpp:817:62:817:65 | p_in | |
| taint.cpp:817:62:817:65 | p_in | taint.cpp:818:20:818:23 | p_in | |
| taint.cpp:818:19:818:23 | * ... | taint.cpp:819:19:819:19 | q | |
| taint.cpp:818:20:818:23 | p_in | taint.cpp:818:19:818:23 | * ... | TAINT |
| taint.cpp:819:3:819:8 | * ... [post update] | taint.cpp:817:42:817:46 | p_out | |
| taint.cpp:819:3:819:8 | * ... [post update] | taint.cpp:819:4:819:8 | p_out [inner post update] | |
| taint.cpp:819:3:819:25 | ... = ... | taint.cpp:819:3:819:8 | * ... [post update] | |
| taint.cpp:819:4:819:8 | p_out | taint.cpp:819:3:819:8 | * ... | TAINT |
| taint.cpp:819:12:819:17 | call to strchr | taint.cpp:819:3:819:25 | ... = ... | |
| taint.cpp:819:19:819:19 | q | taint.cpp:819:12:819:17 | call to strchr | TAINT |
| taint.cpp:819:22:819:24 | 47 | taint.cpp:819:12:819:17 | call to strchr | TAINT |
| taint.cpp:822:33:822:35 | out | taint.cpp:822:33:822:35 | out | |
| taint.cpp:822:33:822:35 | out | taint.cpp:826:27:826:29 | out | |
| taint.cpp:822:50:822:51 | in | taint.cpp:822:50:822:51 | in | |
| taint.cpp:822:50:822:51 | in | taint.cpp:826:33:826:34 | in | |
| taint.cpp:826:26:826:29 | ref arg & ... | taint.cpp:822:33:822:35 | out | |
| taint.cpp:826:26:826:29 | ref arg & ... | taint.cpp:826:27:826:29 | out [inner post update] | |
| taint.cpp:826:27:826:29 | out | taint.cpp:826:26:826:29 | & ... | |
| taint.cpp:826:32:826:34 | ref arg & ... | taint.cpp:822:50:822:51 | in | |
| taint.cpp:826:32:826:34 | ref arg & ... | taint.cpp:826:33:826:34 | in [inner post update] | |
| taint.cpp:826:33:826:34 | in | taint.cpp:826:32:826:34 | & ... | |
| taint.cpp:830:20:830:34 | call to indirect_source | taint.cpp:832:23:832:24 | in | |
| taint.cpp:831:15:831:17 | out | taint.cpp:832:18:832:20 | out | |
| taint.cpp:831:15:831:17 | out | taint.cpp:833:8:833:10 | out | |
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |

View File

@@ -810,4 +810,25 @@ void test_sysalloc() {
auto p3 = SysAllocStringLen((LPOLESTR)indirect_source(), 10);
sink(*p3); // $ ir MISSING: ast
}
char* strchr(const char*, int);
void write_to_const_ptr_ptr(const char **p_out, const char **p_in) {
const char* q = *p_in;
*p_out = strchr(q, '/');
}
void take_const_ptr(const char *out, const char *in) {
// NOTE: We take the address of `out` in `take_const_ptr`'s stack space.
// Assigning to this pointer does not change `out` in
// `test_write_to_const_ptr_ptr`.
write_to_const_ptr_ptr(&out, &in);
}
void test_write_to_const_ptr_ptr() {
const char* in = indirect_source();
const char* out;
take_const_ptr(out, in);
sink(out); // $ SPURIOUS: ast
}

View File

@@ -626,6 +626,11 @@ signatureMatches
| taint.cpp:725:10:725:15 | strtol | (XCHAR *,const XCHAR *,int) | CSimpleStringT | CopyCharsOverlapped | 2 |
| taint.cpp:727:6:727:16 | test_strtol | (char *) | CStringT | CStringT | 0 |
| taint.cpp:785:6:785:15 | fopen_test | (char *) | CStringT | CStringT | 0 |
| taint.cpp:815:7:815:12 | strchr | (LPCOLESTR,int) | CComBSTR | Append | 1 |
| taint.cpp:815:7:815:12 | strchr | (char,int) | CStringT | CStringT | 1 |
| taint.cpp:815:7:815:12 | strchr | (const XCHAR *,int) | CStringT | CStringT | 1 |
| taint.cpp:815:7:815:12 | strchr | (const YCHAR *,int) | CStringT | CStringT | 1 |
| taint.cpp:815:7:815:12 | strchr | (wchar_t,int) | CStringT | CStringT | 1 |
| vector.cpp:333:6:333:35 | vector_iterator_assign_wrapper | (LPCOLESTR,int) | CComBSTR | Append | 1 |
| vector.cpp:333:6:333:35 | vector_iterator_assign_wrapper | (char,int) | CStringT | CStringT | 1 |
| vector.cpp:333:6:333:35 | vector_iterator_assign_wrapper | (const XCHAR *,int) | CStringT | CStringT | 1 |
@@ -2029,6 +2034,12 @@ getParameterTypeName
| taint.cpp:802:6:802:22 | SysAllocStringLen | 0 | const OLECHAR * |
| taint.cpp:802:6:802:22 | SysAllocStringLen | 0 | const wchar_t * |
| taint.cpp:802:6:802:22 | SysAllocStringLen | 1 | unsigned int |
| taint.cpp:815:7:815:12 | strchr | 0 | const char * |
| taint.cpp:815:7:815:12 | strchr | 1 | int |
| taint.cpp:817:6:817:27 | write_to_const_ptr_ptr | 0 | const char ** |
| taint.cpp:817:6:817:27 | write_to_const_ptr_ptr | 1 | const char ** |
| taint.cpp:822:6:822:19 | take_const_ptr | 0 | const char * |
| taint.cpp:822:6:822:19 | take_const_ptr | 1 | const char * |
| vector.cpp:13:6:13:9 | sink | 0 | int |
| vector.cpp:14:27:14:30 | sink | 0 | vector> & |
| vector.cpp:14:27:14:30 | sink | 0 | vector> & |

View File

@@ -1,4 +1,4 @@
edges
subpaths
nodes
subpaths
#select

View File

@@ -49,6 +49,37 @@
| tests.cpp:577:7:577:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:565:7:565:12 | buffer | array |
| tests.cpp:637:6:637:15 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:633:7:633:12 | buffer | array |
| tests.cpp:645:7:645:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:633:7:633:12 | buffer | array |
| tests.cpp:708:3:708:8 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer |
| tests.cpp:712:3:712:8 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer |
| tests.cpp:716:3:716:8 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 16 bytes. | tests.cpp:692:16:692:16 | b | destination buffer |
| tests.cpp:727:2:727:7 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer |
| tests.cpp:753:5:753:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer |
| tests.cpp:756:5:756:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer |
| tests.cpp:760:5:760:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer |
| tests.cpp:761:5:761:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer |
| tests.cpp:763:5:763:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer |
| tests.cpp:764:5:764:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer |
| tests.cpp:774:5:774:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer |
| tests.cpp:777:5:777:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer |
| tests.cpp:795:5:795:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:790:16:790:16 | b | destination buffer |
| tests.cpp:822:5:822:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:801:16:801:16 | b | destination buffer |
| tests.cpp:825:5:825:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:801:16:801:16 | b | destination buffer |
| tests.cpp:827:5:827:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:801:16:801:16 | b | destination buffer |
| tests.cpp:830:5:830:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer |
| tests.cpp:831:5:831:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer |
| tests.cpp:833:5:833:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer |
| tests.cpp:835:5:835:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer |
| tests.cpp:846:5:846:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer |
| tests.cpp:847:5:847:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer |
| tests.cpp:848:5:848:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer |
| tests.cpp:849:5:849:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer |
| tests.cpp:851:5:851:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer |
| tests.cpp:862:5:862:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer |
| tests.cpp:863:5:863:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer |
| tests.cpp:864:5:864:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer |
| tests.cpp:865:5:865:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer |
| tests.cpp:866:5:866:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer |
| tests.cpp:867:5:867:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer |
| tests_restrict.c:12:2:12:7 | call to memcpy | This 'memcpy' operation accesses 2 bytes but the $@ is only 1 byte. | tests_restrict.c:7:6:7:13 | smallbuf | source buffer |
| unions.cpp:26:2:26:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:21:10:21:11 | mu | destination buffer |
| unions.cpp:30:2:30:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:15:7:15:11 | small | destination buffer |

View File

@@ -27,8 +27,8 @@ edges
| main.cpp:9:29:9:32 | *argv | tests_restrict.c:15:41:15:44 | *argv | provenance | |
| main.cpp:9:29:9:32 | tests_restrict_main output argument | main.cpp:10:20:10:23 | **argv | provenance | |
| main.cpp:9:29:9:32 | tests_restrict_main output argument | main.cpp:10:20:10:23 | *argv | provenance | |
| main.cpp:10:20:10:23 | **argv | tests.cpp:689:32:689:35 | **argv | provenance | |
| main.cpp:10:20:10:23 | *argv | tests.cpp:689:32:689:35 | *argv | provenance | |
| main.cpp:10:20:10:23 | **argv | tests.cpp:872:32:872:35 | **argv | provenance | |
| main.cpp:10:20:10:23 | *argv | tests.cpp:872:32:872:35 | *argv | provenance | |
| overflowdestination.cpp:23:45:23:48 | **argv | overflowdestination.cpp:23:45:23:48 | **argv | provenance | |
| overflowdestination.cpp:23:45:23:48 | **argv | overflowdestination.cpp:23:45:23:48 | *argv | provenance | |
| test_buffer_overrun.cpp:32:46:32:49 | **argv | test_buffer_overrun.cpp:32:46:32:49 | **argv | provenance | |
@@ -41,12 +41,12 @@ edges
| tests.cpp:628:14:628:14 | *s [*home] | tests.cpp:628:14:628:19 | *home | provenance | |
| tests.cpp:628:14:628:14 | *s [*home] | tests.cpp:628:16:628:19 | *home | provenance | |
| tests.cpp:628:16:628:19 | *home | tests.cpp:628:14:628:19 | *home | provenance | |
| tests.cpp:689:32:689:35 | **argv | tests.cpp:714:9:714:15 | *access to array | provenance | |
| tests.cpp:689:32:689:35 | **argv | tests.cpp:715:9:715:15 | *access to array | provenance | |
| tests.cpp:689:32:689:35 | *argv | tests.cpp:714:9:714:15 | *access to array | provenance | |
| tests.cpp:689:32:689:35 | *argv | tests.cpp:715:9:715:15 | *access to array | provenance | |
| tests.cpp:714:9:714:15 | *access to array | tests.cpp:613:19:613:24 | *source | provenance | |
| tests.cpp:715:9:715:15 | *access to array | tests.cpp:622:19:622:24 | *source | provenance | |
| tests.cpp:872:32:872:35 | **argv | tests.cpp:897:9:897:15 | *access to array | provenance | |
| tests.cpp:872:32:872:35 | **argv | tests.cpp:898:9:898:15 | *access to array | provenance | |
| tests.cpp:872:32:872:35 | *argv | tests.cpp:897:9:897:15 | *access to array | provenance | |
| tests.cpp:872:32:872:35 | *argv | tests.cpp:898:9:898:15 | *access to array | provenance | |
| tests.cpp:897:9:897:15 | *access to array | tests.cpp:613:19:613:24 | *source | provenance | |
| tests.cpp:898:9:898:15 | *access to array | tests.cpp:622:19:622:24 | *source | provenance | |
| tests_restrict.c:15:41:15:44 | **argv | tests_restrict.c:15:41:15:44 | **argv | provenance | |
| tests_restrict.c:15:41:15:44 | *argv | tests_restrict.c:15:41:15:44 | *argv | provenance | |
nodes
@@ -80,10 +80,10 @@ nodes
| tests.cpp:628:14:628:14 | *s [*home] | semmle.label | *s [*home] |
| tests.cpp:628:14:628:19 | *home | semmle.label | *home |
| tests.cpp:628:16:628:19 | *home | semmle.label | *home |
| tests.cpp:689:32:689:35 | **argv | semmle.label | **argv |
| tests.cpp:689:32:689:35 | *argv | semmle.label | *argv |
| tests.cpp:714:9:714:15 | *access to array | semmle.label | *access to array |
| tests.cpp:715:9:715:15 | *access to array | semmle.label | *access to array |
| tests.cpp:872:32:872:35 | **argv | semmle.label | **argv |
| tests.cpp:872:32:872:35 | *argv | semmle.label | *argv |
| tests.cpp:897:9:897:15 | *access to array | semmle.label | *access to array |
| tests.cpp:898:9:898:15 | *access to array | semmle.label | *access to array |
| tests_restrict.c:15:41:15:44 | **argv | semmle.label | **argv |
| tests_restrict.c:15:41:15:44 | **argv | semmle.label | **argv |
| tests_restrict.c:15:41:15:44 | *argv | semmle.label | *argv |

View File

@@ -685,6 +685,189 @@ int test28(MYSTRUCTREF g)
return memcmp(&g, &_myStruct, sizeof(MYSTRUCT)); // GOOD
}
#define offsetof(s, m) __builtin_offsetof(s, m)
struct HasSomeFields {
unsigned long a;
unsigned long b;
unsigned long c;
void test29() {
memset(&a, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, a)); // GOOD
};
void test30() {
memset(&b, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, b)); // GOOD
};
void test31() {
memset(&c, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, c)); // GOOD
};
void test32() {
memset(&c, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, a)); // BAD
};
void test33() {
memset(&c, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, b)); // BAD
};
void test34() {
memset(&b, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, a)); // BAD
};
void test35() {
memset(&b, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, b) - sizeof(unsigned long)); // GOOD
};
};
void test36() {
HasSomeFields hsf;
memset(&hsf.a, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, a)); // GOOD
memset(&hsf.c, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, a)); // BAD
}
struct AnonUnionInStruct
{
union {
struct {
unsigned int a_1;
unsigned int b_1;
unsigned int c_1;
};
struct {
unsigned int a_2;
unsigned int b_2;
};
};
unsigned int d;
void test37() {
memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // GOOD
memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD
memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD
memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // GOOD
memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD
memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD
memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // BAD
memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD
memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD
memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // BAD
memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD
memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD
memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // BAD
memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // BAD
memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD
memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // BAD
memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD
memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD
memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // GOOD
memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD
memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD
memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // GOOD
memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD
memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD
memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // BAD
memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD
memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD
memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // BAD
memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD
memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD
};
};
struct UnionWithoutStruct
{
union
{
unsigned int a;
};
unsigned int b;
void test37() {
memset(&a, 0, sizeof(UnionWithoutStruct) - offsetof(UnionWithoutStruct, a)); // GOOD
memset(&a, 0, sizeof(UnionWithoutStruct) - offsetof(UnionWithoutStruct, b)); // GOOD
memset(&b, 0, sizeof(UnionWithoutStruct) - offsetof(UnionWithoutStruct, a)); // BAD
};
};
struct ThreeUInts {
unsigned int a;
unsigned int b;
unsigned int c;
};
struct FourUInts {
ThreeUInts inner;
unsigned int x;
};
struct S2 {
FourUInts f;
unsigned u;
void test38() {
memset(&f.inner.a, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // GOOD
memset(&f.inner.a, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD
memset(&f.inner.a, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD
memset(&f.inner.a, 0, sizeof(S2) - offsetof(FourUInts, inner)); // GOOD
memset(&f.inner.a, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD
memset(&f.inner.a, 0, sizeof(S2) - offsetof(S2, f)); // GOOD
memset(&f.inner.a, 0, sizeof(S2) - offsetof(S2, u)); // GOOD
memset(&f.inner.b, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD
memset(&f.inner.b, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD
memset(&f.inner.b, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD
memset(&f.inner.b, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD
memset(&f.inner.b, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD
memset(&f.inner.b, 0, sizeof(S2) - offsetof(S2, f)); // BAD
memset(&f.inner.b, 0, sizeof(S2) - offsetof(S2, u)); // GOOD
memset(&f.inner.c, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD
memset(&f.inner.c, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // BAD
memset(&f.inner.c, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD
memset(&f.inner.c, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD
memset(&f.inner.c, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD
memset(&f.inner.c, 0, sizeof(S2) - offsetof(S2, f)); // BAD
memset(&f.inner.c, 0, sizeof(S2) - offsetof(S2, u)); // GOOD
memset(&f.inner, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // GOOD
memset(&f.inner, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD
memset(&f.inner, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD
memset(&f.inner, 0, sizeof(S2) - offsetof(FourUInts, inner)); // GOOD
memset(&f.inner, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD
memset(&f.inner, 0, sizeof(S2) - offsetof(S2, f)); // GOOD
memset(&f.inner, 0, sizeof(S2) - offsetof(S2, u)); // GOOD
memset(&f.x, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD
memset(&f.x, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // BAD
memset(&f.x, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // BAD
memset(&f.x, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD
memset(&f.x, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD
memset(&f.x, 0, sizeof(S2) - offsetof(S2, f)); // GOOD
memset(&f.x, 0, sizeof(S2) - offsetof(S2, u)); // GOOD
memset(&f, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // GOOD
memset(&f, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD
memset(&f, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD
memset(&f, 0, sizeof(S2) - offsetof(FourUInts, inner)); // GOOD
memset(&f, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD
memset(&f, 0, sizeof(S2) - offsetof(S2, f)); // GOOD
memset(&f, 0, sizeof(S2) - offsetof(S2, u)); // GOOD
memset(&u, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD
memset(&u, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // BAD
memset(&u, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // BAD
memset(&u, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD
memset(&u, 0, sizeof(S2) - offsetof(FourUInts, x)); // BAD
memset(&u, 0, sizeof(S2) - offsetof(S2, f)); // BAD
memset(&u, 0, sizeof(S2) - offsetof(S2, u)); // GOOD
}
};
int tests_main(int argc, char *argv[])
{