Merge branch 'master' into pointer-wraparound-query

This commit is contained in:
Jonas Jensen
2019-11-12 10:22:46 +01:00
545 changed files with 16354 additions and 9278 deletions

View File

@@ -19,6 +19,7 @@ where
pointlessSelfComparison(cmp) and
not nanTest(cmp) and
not overflowTest(cmp) and
not cmp.isFromTemplateInstantiation(_) and
not exists(MacroInvocation mi |
// cmp is in mi
mi.getAnExpandedElement() = cmp and

View File

@@ -0,0 +1,3 @@
bool foo(int n1, unsigned short delta) {
return n1 + delta < n1; // BAD
}

View File

@@ -0,0 +1,4 @@
bool bar(unsigned short n1, unsigned short delta) {
// NB: Comparison is always false
return n1 + delta < n1; // GOOD (but misleading)
}

View File

@@ -0,0 +1,4 @@
#include <limits.h>
bool foo(int n1, unsigned short delta) {
return n1 > INT_MAX - delta; // GOOD
}

View File

@@ -0,0 +1,3 @@
bool bar(unsigned short n1, unsigned short delta) {
return (unsigned short)(n1 + delta) < n1; // GOOD
}

View File

@@ -0,0 +1,115 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
When checking for integer overflow, you may often write tests like
<code>a + b &lt; a</code>. This works fine if <code>a</code> or
<code>b</code> are unsigned integers, since any overflow in the addition
will cause the value to simply "wrap around." However, using
<i>signed</i> integers is problematic because signed overflow has undefined
behavior according to the C and C++ standards. If the addition overflows
and has an undefined result, the comparison will likewise be undefined;
it may produce an unintended result, or may be deleted entirely by an
optimizing compiler.
</p>
</overview>
<recommendation>
<p>
Solutions to this problem can be thought of as falling into one of two
categories: (1) rewrite the signed expression so that overflow cannot occur
but the signedness remains, or (2) rewrite (or cast) the signed expression
into unsigned form.
</p>
<p>
Below we list examples of expressions where signed overflow may
occur, along with proposed solutions. The list should not be
considered exhaustive.
</p>
<p>
Given <code>unsigned short i, delta</code> and <code>i + delta &lt; i</code>,
it is possible to rewrite it as <code>(unsigned short)(i + delta)&nbsp;&lt;&nbsp;i</code>.
Note that <code>i + delta</code>does not actually overflow, due to <code>int</code> promotion
</p>
<p>
Given <code>unsigned short i, delta</code> and <code>i + delta &lt; i</code>,
it is also possible to rewrite it as <code>USHORT_MAX - delta</code>. It must be true
that <code>delta &gt; 0</code> and the <code>limits.h</code> or <code>climits</code>
header has been included.
</p>
<p>
Given <code>int i, delta</code> and <code>i + delta &lt; i</code>,
it is possible to rewrite it as <code>INT_MAX - delta</code>. It must be true
that <code>delta &gt; 0</code> and the <code>limits.h</code> or <code>climits</code>
header has been included.
</p>
<p>
Given <code>int i, delta</code> and <code>i + delta &lt; i</code>,
it is also possible to rewrite it as <code>(unsigned)i + delta &lt; i</code>.
Note that program semantics are affected by this change.
</p>
<p>
Given <code>int i, delta</code> and <code>i + delta &lt; i</code>,
it is also possible to rewrite it as <code>unsigned int i, delta</code> and
<code>i + delta &lt; i</code>. Note that program semantics are
affected by this change.
</p>
</recommendation>
<example>
<p>
In the following example, even though <code>delta</code> has been declared
<code>unsigned short</code>, C/C++ type promotion rules require that its
type is promoted to the larger type used in the addition and comparison,
namely a <code>signed int</code>. Addition is performed on
signed integers, and may have undefined behavior if an overflow occurs.
As a result, the entire (comparison) expression may also have an undefined
result.
</p>
<sample src="SignedOverflowCheck-bad1.cpp" />
<p>
The following example builds upon the previous one. Instead of
performing an addition (which could overflow), we have re-framed the
solution so that a subtraction is used instead. Since <code>delta</code>
is promoted to a <code>signed int</code> and <code>INT_MAX</code> denotes
the largest possible positive value for an <code>signed int</code>,
the expression <code>INT_MAX - delta</code> can never be less than zero
or more than <code>INT_MAX</code>. Hence, any overflow and underflow
are avoided.
</p>
<sample src="SignedOverflowCheck-good1.cpp" />
<p>
In the following example, even though both <code>n</code> and <code>delta</code>
have been declared <code>unsigned short</code>, both are promoted to
<code>signed int</code> prior to addition. Because we started out with the
narrower <code>short</code> type, the addition is guaranteed not to overflow
and is therefore defined. But the fact that <code>n1 + delta</code> never
overflows means that the condition <code>n1 + delta &lt; n1</code> will never
hold true, which likely is not what the programmer intended. (see also the
<code>cpp/bad-addition-overflow-check</code> query).
</p>
<sample src="SignedOverflowCheck-bad2.cpp" />
<p>
The next example provides a solution to the previous one. Even though
<code>i + delta</code> does not overflow, casting it to an
<code>unsigned short</code> truncates the addition modulo 2^16,
so that <code>unsigned short</code> "wrap around" may now be observed.
Furthermore, since the left-hand side is now of type <code>unsigned short</code>,
the right-hand side does not need to be promoted to a <code>signed int</code>.
</p>
<sample src="SignedOverflowCheck-good2.cpp" />
</example>
<references>
<li><a href="http://c-faq.com/expr/preservingrules.html">comp.lang.c FAQ list · Question 3.19 (Preserving rules)</a></li>
<li><a href="https://wiki.sei.cmu.edu/confluence/display/c/INT31-C.+Ensure+that+integer+conversions+do+not+result+in+lost+or+misinterpreted+data">INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data</a></li>
<li>W. Dietz, P. Li, J. Regehr, V. Adve. <a href="https://www.cs.utah.edu/~regehr/papers/overflow12.pdf">Understanding Integer Overflow in C/C++</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,31 @@
/**
* @name Undefined result of signed test for overflow
* @description Testing for overflow by adding a value to a variable
* to see if it "wraps around" works only for
* unsigned integer values.
* @kind problem
* @problem.severity warning
* @precision high
* @id cpp/signed-overflow-check
* @tags reliability
* security
*/
import cpp
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
from RelationalOperation ro, AddExpr add, Expr expr1, Expr expr2
where
ro.getAnOperand() = add and
add.getAnOperand() = expr1 and
ro.getAnOperand() = expr2 and
globalValueNumber(expr1) = globalValueNumber(expr2) and
add.getUnspecifiedType().(IntegralType).isSigned() and
not exists(MacroInvocation mi | mi.getAnAffectedElement() = add) and
exprMightOverflowPositively(add) and
exists(Compilation c | c.getAFileCompiled() = ro.getFile() |
not c.getAnArgument() = "-fwrapv" and
not c.getAnArgument() = "-fno-strict-overflow"
)
select ro, "Testing for signed overflow may produce undefined results."

View File

@@ -14,7 +14,7 @@ byte order function, such as <code>ntohl</code>.
The use of a network-to-host byte order function is therefore a good indicator that the returned
value is unvalidated data retrieved from the network, and should not be used without further
validation. In particular, the returned value should not be used as an array index or array length
value without validation, which may result in a buffer overflow vulnerability.
value without validation, as this could result in a buffer overflow vulnerability.
</p>
</overview>

View File

@@ -13,32 +13,33 @@ import semmle.code.cpp.security.boostorg.asio.protocols
class ExistsAnyFlowConfig extends DataFlow::Configuration {
ExistsAnyFlowConfig() { this = "ExistsAnyFlowConfig" }
override predicate isSource(DataFlow::Node source) { any() }
override predicate isSource(DataFlow::Node source) {
exists(BoostorgAsio::SslContextClass c | c.getAContructorCall() = source.asExpr())
}
override predicate isSink(DataFlow::Node sink) { any() }
override predicate isSink(DataFlow::Node sink) {
exists(BoostorgAsio::SslSetOptionsFunction f, FunctionCall fcSetOptions |
f.getACallToThisFunction() = fcSetOptions and
fcSetOptions.getQualifier() = sink.asExpr()
)
}
}
bindingset[flag]
predicate isOptionSet(ConstructorCall cc, int flag, FunctionCall fcSetOptions) {
exists(
BoostorgAsio::SslContextFlowsToSetOptionConfig config, ExistsAnyFlowConfig testConfig,
Expr optionsSink
|
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
exists(VariableAccess contextSetOptions |
testConfig.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(contextSetOptions)) and
exists(BoostorgAsio::SslSetOptionsFunction f | f.getACallToThisFunction() = fcSetOptions |
contextSetOptions = fcSetOptions.getQualifier() and
forall(
Expr optionArgument, BoostorgAsio::SslOptionConfig optionArgConfig,
Expr optionArgumentSource
|
optionArgument = fcSetOptions.getArgument(0) and
optionArgConfig
.hasFlow(DataFlow::exprNode(optionArgumentSource), DataFlow::exprNode(optionArgument))
|
optionArgument.getValue().toInt().bitShiftRight(16).bitAnd(flag) = flag
)
exists(ExistsAnyFlowConfig anyFlowConfig, VariableAccess contextSetOptions |
anyFlowConfig.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(contextSetOptions)) and
exists(BoostorgAsio::SslSetOptionsFunction f | f.getACallToThisFunction() = fcSetOptions |
contextSetOptions = fcSetOptions.getQualifier() and
forall(
Expr optionArgument, BoostorgAsio::SslOptionConfig optionArgConfig,
Expr optionArgumentSource
|
optionArgument = fcSetOptions.getArgument(0) and
optionArgConfig
.hasFlow(DataFlow::exprNode(optionArgumentSource), DataFlow::exprNode(optionArgument))
|
optionArgument.getValue().toInt().bitShiftRight(16).bitAnd(flag) = flag
)
)
)
@@ -46,43 +47,18 @@ predicate isOptionSet(ConstructorCall cc, int flag, FunctionCall fcSetOptions) {
bindingset[flag]
predicate isOptionNotSet(ConstructorCall cc, int flag) {
not exists(
BoostorgAsio::SslContextFlowsToSetOptionConfig config, ExistsAnyFlowConfig testConfig,
Expr optionsSink
|
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
exists(VariableAccess contextSetOptions |
testConfig.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(contextSetOptions)) and
exists(FunctionCall fcSetOptions, BoostorgAsio::SslSetOptionsFunction f |
f.getACallToThisFunction() = fcSetOptions
|
contextSetOptions = fcSetOptions.getQualifier() and
forall(
Expr optionArgument, BoostorgAsio::SslOptionConfig optionArgConfig,
Expr optionArgumentSource
|
optionArgument = fcSetOptions.getArgument(0) and
optionArgConfig
.hasFlow(DataFlow::exprNode(optionArgumentSource), DataFlow::exprNode(optionArgument))
|
optionArgument.getValue().toInt().bitShiftRight(16).bitAnd(flag) = flag
)
)
)
)
not exists(FunctionCall fcSetOptions | isOptionSet(cc, flag, fcSetOptions))
}
from
BoostorgAsio::SslContextCallTlsProtocolConfig configConstructor,
BoostorgAsio::SslContextFlowsToSetOptionConfig config, Expr protocolSource, Expr protocolSink,
ConstructorCall cc, Expr e, string msg
BoostorgAsio::SslContextCallTlsProtocolConfig configConstructor, Expr protocolSource,
Expr protocolSink, ConstructorCall cc, Expr e, string msg
where
configConstructor.hasFlow(DataFlow::exprNode(protocolSource), DataFlow::exprNode(protocolSink)) and
cc.getArgument(0) = protocolSink and
(
BoostorgAsio::isExprSslV23BoostProtocol(protocolSource) and
not exists(Expr optionsSink |
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
not (
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoSsl3(), _) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1(), _) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_1(), _) and
@@ -91,8 +67,7 @@ where
or
BoostorgAsio::isExprTlsBoostProtocol(protocolSource) and
not BoostorgAsio::isExprSslV23BoostProtocol(protocolSource) and
not exists(Expr optionsSink |
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
not (
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1(), _) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_1(), _) and
isOptionNotSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2())

View File

@@ -126,7 +126,7 @@ class SALParameter extends Parameter {
}
/**
* A SAL element, i.e. a SAL annotation or a declaration entry
* A SAL element, that is, a SAL annotation or a declaration entry
* that may have SAL annotations.
*/
library class SALElement extends Element {

View File

@@ -34,7 +34,7 @@ characters before writing to the HTML page.</p>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet">XSS
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html">XSS
(Cross Site Scripting) Prevention Cheat Sheet</a>.
</li>
<li>

View File

@@ -37,7 +37,7 @@ which is then subsequently accessed to fetch properties of the device. However,
check the return value from the function call to <code>initDeviceConfig</code>. If the
device number passed to the <code>notify</code> function was invalid, the
<code>initDeviceConfig</code> function will leave the <code>config</code> variable uninitialized,
which would result in the <code>notify</code> function accessing uninitialized memory.</p>
which will result in the <code>notify</code> function accessing uninitialized memory.</p>
<sample src="ConditionallyUninitializedVariableBad.c" />

View File

@@ -2,7 +2,7 @@
* @name Conditionally uninitialized variable
* @description When an initialization function is used to initialize a local variable, but the
* returned status code is not checked, the variable may be left in an uninitialized
* state, and reading the variable may result in undefined behaviour.
* state, and reading the variable may result in undefined behavior.
* @kind problem
* @problem.severity warning
* @opaque-id SM02313

View File

@@ -19,7 +19,7 @@ int notify(int deviceNumber) {
DeviceConfig config;
initDeviceConfig(&config, deviceNumber);
// BAD: Using config without checking the status code that is returned
if (config->isEnabled) {
notifyChannel(config->channel);
if (config.isEnabled) {
notifyChannel(config.channel);
}
}
}

View File

@@ -20,8 +20,8 @@ void notify(int deviceNumber) {
int statusCode = initDeviceConfig(&config, deviceNumber);
if (statusCode == 0) {
// GOOD: Status code returned by initialization function is checked, so this is safe
if (config->isEnabled) {
notifyChannel(config->channel);
if (config.isEnabled) {
notifyChannel(config.channel);
}
}
}
}

View File

@@ -89,9 +89,9 @@ class ParameterNullCheck extends ParameterCheck {
(
va = this.(NotExpr).getOperand() or
va = any(EQExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
va = getAssertedFalseCondition(this) or
va = getCheckedFalseCondition(this) or
va = any(NEExpr eq |
eq = getAssertedFalseCondition(this) and eq.getAnOperand().getValue() = "0"
eq = getCheckedFalseCondition(this) and eq.getAnOperand().getValue() = "0"
).getAnOperand()
)
or
@@ -101,7 +101,7 @@ class ParameterNullCheck extends ParameterCheck {
va = this or
va = any(NEExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
va = any(EQExpr eq |
eq = getAssertedFalseCondition(this) and eq.getAnOperand().getValue() = "0"
eq = getCheckedFalseCondition(this) and eq.getAnOperand().getValue() = "0"
).getAnOperand()
)
)
@@ -567,7 +567,7 @@ Expr getAnInitializedArgument(Call call) { result = call.getArgument(initialized
* the call, under the given context and evidence.
*/
pragma[nomagic]
int conditionallyInitializedArgument(
private int conditionallyInitializedArgument(
Call call, ConditionalInitializationFunction target, Context c, Evidence e
) {
target = getTarget(call) and
@@ -588,7 +588,7 @@ Expr getAConditionallyInitializedArgument(
/**
* Gets the type signature for the functions parameters.
*/
string typeSig(Function f) {
private string typeSig(Function f) {
result = concat(int i, Type pt |
pt = f.getParameter(i).getType()
|
@@ -599,7 +599,7 @@ string typeSig(Function f) {
/**
* Holds where qualifiedName and typeSig make up the signature for the function.
*/
predicate functionSignature(Function f, string qualifiedName, string typeSig) {
private predicate functionSignature(Function f, string qualifiedName, string typeSig) {
qualifiedName = f.getQualifiedName() and
typeSig = typeSig(f)
}
@@ -611,7 +611,7 @@ predicate functionSignature(Function f, string qualifiedName, string typeSig) {
* This is useful for identifying call to target dependencies across libraries, where the libraries
* are never statically linked together.
*/
Function getAPossibleDefinition(Function undefinedFunction) {
private Function getAPossibleDefinition(Function undefinedFunction) {
not undefinedFunction.isDefined() and
exists(string qn, string typeSig |
functionSignature(undefinedFunction, qn, typeSig) and functionSignature(result, qn, typeSig)
@@ -620,32 +620,47 @@ Function getAPossibleDefinition(Function undefinedFunction) {
}
/**
* Gets a possible target for the Call, using the name and parameter matching if we did not associate
* Helper predicate for `getTarget`, that computes possible targets of a `Call`.
*
* If there is at least one defined target after performing some simple virtual dispatch
* resolution, then the result is all the defined targets.
*/
private Function getTarget1(Call c) {
result = VirtualDispatch::getAViableTarget(c) and
result.isDefined()
}
/**
* Helper predicate for `getTarget`, that computes possible targets of a `Call`.
*
* If we can use the heuristic matching of functions to find definitions for some of the viable
* targets, return those.
*/
private Function getTarget2(Call c) {
not exists(getTarget1(c)) and
result = getAPossibleDefinition(VirtualDispatch::getAViableTarget(c))
}
/**
* Helper predicate for `getTarget`, that computes possible targets of a `Call`.
*
* Otherwise, the result is the undefined `Function` instances.
*/
private Function getTarget3(Call c) {
not exists(getTarget1(c)) and
not exists(getTarget2(c)) and
result = VirtualDispatch::getAViableTarget(c)
}
/**
* Gets a possible target for the `Call`, using the name and parameter matching if we did not associate
* this call with a specific definition at link or compile time, and performing simple virtual
* dispatch resolution.
*/
Function getTarget(Call c) {
if VirtualDispatch::getAViableTarget(c).isDefined()
then
/*
* If there is at least one defined target after performing some simple virtual dispatch
* resolution, then the result is all the defined targets.
*/
result = VirtualDispatch::getAViableTarget(c) and
result.isDefined()
else
if exists(getAPossibleDefinition(VirtualDispatch::getAViableTarget(c)))
then
/*
* If we can use the heuristic matching of functions to find definitions for some of the viable
* targets, return those.
*/
result = getAPossibleDefinition(VirtualDispatch::getAViableTarget(c))
else
// Otherwise, the result is the undefined `Function` instances
result = VirtualDispatch::getAViableTarget(c)
result = getTarget1(c) or
result = getTarget2(c) or
result = getTarget3(c)
}
/**
@@ -669,7 +684,7 @@ FieldAccess getAFieldAccess(Variable v) {
}
/**
* Gets a condition which is asserted to be false by the given `ne` expression, according to this pattern:
* Gets a condition which is checked to be false by the given `ne` expression, according to this pattern:
* ```
* int a = !!result;
* if (!a) { // <- ne
@@ -677,7 +692,7 @@ FieldAccess getAFieldAccess(Variable v) {
* }
* ```
*/
Expr getAssertedFalseCondition(NotExpr ne) {
private Expr getCheckedFalseCondition(NotExpr ne) {
exists(LocalVariable v |
result = v.getInitializer().getExpr().(NotExpr).getOperand().(NotExpr).getOperand() and
ne.getOperand() = v.getAnAccess() and

View File

@@ -605,15 +605,6 @@ class Class extends UserType {
class_instantiation(underlyingElement(this), unresolveElement(c))
}
/**
* Gets the `i`th template argument used to instantiate this class from a
* class template. When called on a class template, this will return the
* `i`th template parameter.
*/
override Type getTemplateArgument(int i) {
class_template_argument(underlyingElement(this), i, unresolveElement(result))
}
/**
* Holds if this class/struct is polymorphic (has a virtual function, or
* inherits one).
@@ -623,7 +614,7 @@ class Class extends UserType {
}
override predicate involvesTemplateParameter() {
getATemplateArgument().involvesTemplateParameter()
getATemplateArgument().(Type).involvesTemplateParameter()
}
/** Holds if this class, struct or union was declared 'final'. */

View File

@@ -193,20 +193,83 @@ abstract class Declaration extends Locatable, @declaration {
/**
* Gets a template argument used to instantiate this declaration from a template.
* When called on a template, this will return a template parameter.
* When called on a template, this will return a template parameter type for
* both typed and non-typed parameters.
*/
final Type getATemplateArgument() { result = getTemplateArgument(_) }
final Locatable getATemplateArgument() { result = getTemplateArgument(_) }
/**
* Gets a template argument used to instantiate this declaration from a template.
* When called on a template, this will return a non-typed template
* parameter value.
*/
final Locatable getATemplateArgumentKind() { result = getTemplateArgumentKind(_) }
/**
* Gets the `i`th template argument used to instantiate this declaration from a
* template. When called on a template, this will return the `i`th template parameter.
* template.
*
* For example:
*
* `template<typename T, T X> class Foo;`
*
* Will have `getTemplateArgument(0)` return `T`, and
* `getTemplateArgument(1)` return `X`.
*
* `Foo<int, 1> bar;
*
* Will have `getTemplateArgument())` return `int`, and
* `getTemplateArgument(1)` return `1`.
*/
Type getTemplateArgument(int index) { none() }
final Locatable getTemplateArgument(int index) {
if exists(getTemplateArgumentValue(index))
then result = getTemplateArgumentValue(index)
else result = getTemplateArgumentType(index)
}
/**
* Gets the `i`th template argument value used to instantiate this declaration
* from a template. When called on a template, this will return the `i`th template
* parameter value if it exists.
*
* For example:
*
* `template<typename T, T X> class Foo;`
*
* Will have `getTemplateArgumentKind(1)` return `T`, and no result for
* `getTemplateArgumentKind(0)`.
*
* `Foo<int, 10> bar;
*
* Will have `getTemplateArgumentKind(1)` return `int`, and no result for
* `getTemplateArgumentKind(0)`.
*/
final Locatable getTemplateArgumentKind(int index) {
if exists(getTemplateArgumentValue(index))
then result = getTemplateArgumentType(index)
else none()
}
/** Gets the number of template arguments for this declaration. */
final int getNumberOfTemplateArguments() {
result = count(int i | exists(getTemplateArgument(i)))
}
private Type getTemplateArgumentType(int index) {
class_template_argument(underlyingElement(this), index, unresolveElement(result))
or
function_template_argument(underlyingElement(this), index, unresolveElement(result))
or
variable_template_argument(underlyingElement(this), index, unresolveElement(result))
}
private Expr getTemplateArgumentValue(int index) {
class_template_argument_value(underlyingElement(this), index, unresolveElement(result))
or
function_template_argument_value(underlyingElement(this), index, unresolveElement(result))
or
variable_template_argument_value(underlyingElement(this), index, unresolveElement(result))
}
}
/**

View File

@@ -343,15 +343,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
function_instantiation(underlyingElement(this), unresolveElement(f))
}
/**
* Gets the `i`th template argument used to instantiate this function from a
* function template. When called on a function template, this will return the
* `i`th template parameter.
*/
override Type getTemplateArgument(int index) {
function_template_argument(underlyingElement(this), index, unresolveElement(result))
}
/**
* Holds if this function is defined in several files. This is illegal in
* C (though possible in some C++ compilers), and likely indicates that

View File

@@ -1,9 +1,8 @@
import cpp
/**
* Gets a `Field` that is nested within the given `Struct`.
*
* This identifies `Field`s which are located in the same memory
* Gets a `Field` that is within the given `Struct`, either directly or nested
* inside one or more levels of member structs.
*/
private Field getANestedField(Struct s) {
result = s.getAField()
@@ -15,7 +14,7 @@ private Field getANestedField(Struct s) {
}
/**
* Unwraps a series of field accesses to determine the inner-most qualifier.
* Unwraps a series of field accesses to determine the outer-most qualifier.
*/
private Expr getUltimateQualifier(FieldAccess fa) {
exists(Expr qualifier | qualifier = fa.getQualifier() |

View File

@@ -35,6 +35,14 @@ private string getParameterTypeString(Type parameterType) {
else result = parameterType.(DumpType).getTypeIdentityString()
}
private string getTemplateArgumentString(Declaration d, int i) {
if exists(d.getTemplateArgumentKind(i))
then
result = d.getTemplateArgumentKind(i).(DumpType).getTypeIdentityString() + " " +
d.getTemplateArgument(i)
else result = d.getTemplateArgument(i).(DumpType).getTypeIdentityString()
}
/**
* A `Declaration` extended to add methods for generating strings useful only for dumps and debugging.
*/
@@ -56,7 +64,7 @@ abstract private class DumpDeclaration extends Declaration {
strictconcat(int i |
exists(this.getTemplateArgument(i))
|
this.getTemplateArgument(i).(DumpType).getTypeIdentityString(), ", " order by i
getTemplateArgumentString(this, i), ", " order by i
) + ">"
else result = ""
}

View File

@@ -210,7 +210,7 @@ class Type extends Locatable, @type {
// A function call that provides an explicit template argument that refers to T uses T.
// We exclude calls within instantiations, since they do not appear directly in the source.
exists(FunctionCall c |
c.getAnExplicitTemplateArgument().refersTo(this) and
c.getAnExplicitTemplateArgument().(Type).refersTo(this) and
result = c and
not c.getEnclosingFunction().isConstructedFrom(_)
)

View File

@@ -155,15 +155,6 @@ class Variable extends Declaration, @variable {
variable_instantiation(underlyingElement(this), unresolveElement(v))
}
/**
* Gets the `i`th template argument used to instantiate this variable from a
* variable template. When called on a variable template, this will return the
* `i`th template parameter.
*/
override Type getTemplateArgument(int index) {
variable_template_argument(underlyingElement(this), index, unresolveElement(result))
}
/**
* Holds if this is a compiler-generated variable. For example, a
* [range-based for loop](http://en.cppreference.com/w/cpp/language/range-for)

View File

@@ -8,25 +8,32 @@ import semmle.code.cpp.commons.StringAnalysis
import semmle.code.cpp.models.interfaces.FormattingFunction
import semmle.code.cpp.models.implementations.Printf
class PrintfFormatAttribute extends FormatAttribute {
PrintfFormatAttribute() {
getArchetype() = "printf" or
getArchetype() = "__printf__"
}
}
/**
* A function that can be identified as a `printf` style formatting
* function by its use of the GNU `format` attribute.
*/
class AttributeFormattingFunction extends FormattingFunction {
FormatAttribute printf_attrib;
override string getCanonicalQLClass() { result = "AttributeFormattingFunction" }
AttributeFormattingFunction() {
printf_attrib = getAnAttribute() and
(
printf_attrib.getArchetype() = "printf" or
printf_attrib.getArchetype() = "__printf__"
) and
exists(printf_attrib.getFirstFormatArgIndex()) // exclude `vprintf` style format functions
exists(PrintfFormatAttribute printf_attrib |
printf_attrib = getAnAttribute() and
exists(printf_attrib.getFirstFormatArgIndex()) // exclude `vprintf` style format functions
)
}
override int getFormatParameterIndex() { result = printf_attrib.getFormatIndex() }
override int getFormatParameterIndex() {
forex(PrintfFormatAttribute printf_attrib | printf_attrib = getAnAttribute() |
result = printf_attrib.getFormatIndex()
)
}
}
/**
@@ -124,15 +131,17 @@ class FormattingFunctionCall extends Expr {
}
/**
* Gets the argument corresponding to the nth conversion specifier
* Gets the argument corresponding to the nth conversion specifier.
*/
Expr getConversionArgument(int n) {
exists(FormatLiteral fl, int b, int o |
exists(FormatLiteral fl |
fl = this.getFormat() and
b = sum(int i, int toSum | i < n and toSum = fl.getNumArgNeeded(i) | toSum) and
o = fl.getNumArgNeeded(n) and
o > 0 and
result = this.getFormatArgument(b + o - 1)
(
result = this.getFormatArgument(fl.getParameterFieldValue(n))
or
result = this.getFormatArgument(fl.getFormatArgumentIndexFor(n, 2)) and
not exists(fl.getParameterFieldValue(n))
)
)
}
@@ -142,11 +151,14 @@ class FormattingFunctionCall extends Expr {
* an explicit minimum field width).
*/
Expr getMinFieldWidthArgument(int n) {
exists(FormatLiteral fl, int b |
exists(FormatLiteral fl |
fl = this.getFormat() and
b = sum(int i, int toSum | i < n and toSum = fl.getNumArgNeeded(i) | toSum) and
fl.hasImplicitMinFieldWidth(n) and
result = this.getFormatArgument(b)
(
result = this.getFormatArgument(fl.getMinFieldWidthParameterFieldValue(n))
or
result = this.getFormatArgument(fl.getFormatArgumentIndexFor(n, 0)) and
not exists(fl.getMinFieldWidthParameterFieldValue(n))
)
)
}
@@ -156,12 +168,14 @@ class FormattingFunctionCall extends Expr {
* precision).
*/
Expr getPrecisionArgument(int n) {
exists(FormatLiteral fl, int b, int o |
exists(FormatLiteral fl |
fl = this.getFormat() and
b = sum(int i, int toSum | i < n and toSum = fl.getNumArgNeeded(i) | toSum) and
(if fl.hasImplicitMinFieldWidth(n) then o = 1 else o = 0) and
fl.hasImplicitPrecision(n) and
result = this.getFormatArgument(b + o)
(
result = this.getFormatArgument(fl.getPrecisionParameterFieldValue(n))
or
result = this.getFormatArgument(fl.getFormatArgumentIndexFor(n, 1)) and
not exists(fl.getPrecisionParameterFieldValue(n))
)
)
}
@@ -361,6 +375,14 @@ class FormatLiteral extends Literal {
*/
string getParameterField(int n) { this.parseConvSpec(n, _, result, _, _, _, _, _) }
/**
* Gets the parameter field of the nth conversion specifier (if it has one) as a
* zero-based number.
*/
int getParameterFieldValue(int n) {
result = this.getParameterField(n).regexpCapture("([0-9]*)\\$", 1).toInt() - 1
}
/**
* Gets the flags of the nth conversion specifier.
*/
@@ -430,6 +452,14 @@ class FormatLiteral extends Literal {
*/
int getMinFieldWidth(int n) { result = this.getMinFieldWidthOpt(n).toInt() }
/**
* Gets the zero-based parameter number of the minimum field width of the nth
* conversion specifier, if it is implicit and uses a parameter field (such as `*1$`).
*/
int getMinFieldWidthParameterFieldValue(int n) {
result = this.getMinFieldWidthOpt(n).regexpCapture("\\*([0-9]*)\\$", 1).toInt() - 1
}
/**
* Gets the precision of the nth conversion specifier (empty string if none is given).
*/
@@ -460,6 +490,14 @@ class FormatLiteral extends Literal {
else result = this.getPrecisionOpt(n).regexpCapture("\\.([0-9]*)", 1).toInt()
}
/**
* Gets the zero-based parameter number of the precision of the nth conversion
* specifier, if it is implicit and uses a parameter field (such as `*1$`).
*/
int getPrecisionParameterFieldValue(int n) {
result = this.getPrecisionOpt(n).regexpCapture("\\.\\*([0-9]*)\\$", 1).toInt() - 1
}
/**
* Gets the length flag of the nth conversion specifier.
*/
@@ -777,19 +815,49 @@ class FormatLiteral extends Literal {
)
}
/**
* Holds if the nth conversion specifier of this format string (if `mode = 2`), it's
* minimum field width (if `mode = 0`) or it's precision (if `mode = 1`) requires a
* format argument.
*
* Most conversion specifiers require a format argument, whereas minimum field width
* and precision only require a format argument if they are present and a `*` was
* used for it's value in the format string.
*/
private predicate hasFormatArgumentIndexFor(int n, int mode) {
mode = 0 and
this.hasImplicitMinFieldWidth(n)
or
mode = 1 and
this.hasImplicitPrecision(n)
or
mode = 2 and
exists(this.getConvSpecOffset(n)) and
not this.getConversionChar(n) = "m"
}
/**
* Gets the computed format argument index for the nth conversion specifier of this
* format string (if `mode = 2`), it's minimum field width (if `mode = 0`) or it's
* precision (if `mode = 1`). Has no result if that element is not present. Does
* not account for positional arguments (`$`).
*/
int getFormatArgumentIndexFor(int n, int mode) {
hasFormatArgumentIndexFor(n, mode) and
(3 * n) + mode = rank[result + 1](int n2, int mode2 |
hasFormatArgumentIndexFor(n2, mode2)
|
(3 * n2) + mode2
)
}
/**
* Gets the number of arguments required by the nth conversion specifier
* of this format string.
*/
int getNumArgNeeded(int n) {
exists(this.getConvSpecOffset(n)) and
not this.getConversionChar(n) = "%" and
exists(int n1, int n2, int n3 |
(if this.hasImplicitMinFieldWidth(n) then n1 = 1 else n1 = 0) and
(if this.hasImplicitPrecision(n) then n2 = 1 else n2 = 0) and
(if this.getConversionChar(n) = "m" then n3 = 0 else n3 = 1) and
result = n1 + n2 + n3
)
result = count(int mode | hasFormatArgumentIndexFor(n, mode))
}
/**
@@ -801,7 +869,7 @@ class FormatLiteral extends Literal {
// At least one conversion specifier has a parameter field, in which case,
// they all should have.
result = max(string s | this.getParameterField(_) = s + "$" | s.toInt())
else result = sum(int n, int toSum | toSum = this.getNumArgNeeded(n) | toSum)
else result = count(int n, int mode | hasFormatArgumentIndexFor(n, mode))
}
/**

View File

@@ -28,6 +28,19 @@ module VirtualDispatch {
not result.hasName("IUnknown")
}
/**
* Helper predicate for `getAViableTarget`, which computes the viable targets for
* virtual calls based on the qualifier type.
*/
private Function getAViableVirtualCallTarget(Class qualifierType, MemberFunction staticTarget) {
exists(Class qualifierSubType |
result = getAPossibleImplementation(staticTarget) and
qualifierType = qualifierSubType.getABaseClass*() and
mayInherit(qualifierSubType, result) and
not cannotInherit(qualifierSubType, result)
)
}
/**
* Gets a viable target for the given function call.
*
@@ -42,18 +55,9 @@ module VirtualDispatch {
* If `c` is not a virtual call, the result will be `c.getTarget()`.
*/
Function getAViableTarget(Call c) {
exists(Function staticTarget | staticTarget = c.getTarget() |
if c.(FunctionCall).isVirtual() and staticTarget instanceof MemberFunction
then
exists(Class qualifierType, Class qualifierSubType |
result = getAPossibleImplementation(staticTarget) and
qualifierType = getCallQualifierType(c) and
qualifierType = qualifierSubType.getABaseClass*() and
mayInherit(qualifierSubType, result) and
not cannotInherit(qualifierSubType, result)
)
else result = staticTarget
)
if c.(FunctionCall).isVirtual() and c.getTarget() instanceof MemberFunction
then result = getAViableVirtualCallTarget(getCallQualifierType(c), c.getTarget())
else result = c.getTarget()
}
/** Holds if `f` is declared in `c` or a transitive base class of `c`. */
@@ -63,7 +67,7 @@ module VirtualDispatch {
/**
* Holds if `c` cannot inherit the member function `f`,
* i.e. `c` or one of its supertypes overrides `f`.
* that is, `c` or one of its supertypes overrides `f`.
*/
private predicate cannotInherit(Class c, MemberFunction f) {
exists(Class overridingType, MemberFunction override |

View File

@@ -139,17 +139,29 @@ class FunctionCall extends Call, @funbindexpr {
override string getCanonicalQLClass() { result = "FunctionCall" }
/** Gets an explicit template argument for this call. */
Type getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
/** Gets an explicit template argument value for this call. */
Locatable getAnExplicitTemplateArgumentKind() { result = getExplicitTemplateArgumentKind(_) }
/** Gets a template argument for this call. */
Type getATemplateArgument() { result = getTarget().getATemplateArgument() }
Locatable getATemplateArgument() { result = getTarget().getATemplateArgument() }
/** Gets a template argument value for this call. */
Locatable getATemplateArgumentKind() { result = getTarget().getATemplateArgumentKind() }
/** Gets the nth explicit template argument for this call. */
Type getExplicitTemplateArgument(int n) {
Locatable getExplicitTemplateArgument(int n) {
n < getNumberOfExplicitTemplateArguments() and
result = getTemplateArgument(n)
}
/** Gets the nth explicit template argument value for this call. */
Locatable getExplicitTemplateArgumentKind(int n) {
n < getNumberOfExplicitTemplateArguments() and
result = getTemplateArgumentKind(n)
}
/** Gets the number of explicit template arguments for this call. */
int getNumberOfExplicitTemplateArguments() {
if numtemplatearguments(underlyingElement(this), _)
@@ -161,7 +173,10 @@ class FunctionCall extends Call, @funbindexpr {
int getNumberOfTemplateArguments() { result = count(int i | exists(getTemplateArgument(i))) }
/** Gets the nth template argument for this call (indexed from 0). */
Type getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) }
Locatable getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) }
/** Gets the nth template argument value for this call (indexed from 0). */
Locatable getTemplateArgumentKind(int n) { result = getTarget().getTemplateArgumentKind(n) }
/** Holds if any template arguments for this call are implicit / deduced. */
predicate hasImplicitTemplateArguments() {

View File

@@ -2,6 +2,7 @@ import cpp
import semmle.code.cpp.security.Security
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
/**
* A predictable instruction is one where an external user can predict
@@ -145,7 +146,8 @@ GlobalOrNamespaceVariable globalVarFromId(string id) {
}
Function resolveCall(Call call) {
// TODO: improve virtual dispatch. This will help in the test for
// `UncontrolledProcessOperation.ql`.
result = call.getTarget()
exists(CallInstruction callInstruction |
callInstruction.getAST() = call and
result = Dispatch::viableCallable(callInstruction)
)
}

View File

@@ -1,5 +1,6 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
Function viableImpl(CallInstruction call) { result = viableCallable(call) }
@@ -20,6 +21,58 @@ Function viableCallable(CallInstruction call) {
functionSignatureWithBody(qualifiedName, nparams, result) and
strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1
)
or
// Rudimentary virtual dispatch support. It's essentially local data flow
// where the source is a derived-to-base conversion and the target is the
// qualifier of a call.
exists(Class derived, DataFlow::Node thisArgument |
nodeMayHaveClass(derived, thisArgument) and
overrideMayAffectCall(derived, thisArgument, _, result, call)
)
}
/**
* Holds if `call` is a virtual function call with qualifier `thisArgument` in
* `enclosingFunction`, whose static target is overridden by
* `overridingFunction` in `overridingClass`.
*/
pragma[noinline]
private predicate overrideMayAffectCall(
Class overridingClass, DataFlow::Node thisArgument, Function enclosingFunction,
MemberFunction overridingFunction, CallInstruction call
) {
call.getEnclosingFunction() = enclosingFunction and
overridingFunction.getAnOverriddenFunction+() = call.getStaticCallTarget() and
overridingFunction.getDeclaringType() = overridingClass and
thisArgument = DataFlow::instructionNode(call.getThisArgument())
}
/**
* Holds if `node` may have dynamic class `derived`, where `derived` is a class
* that may affect virtual dispatch within the enclosing function.
*
* For the sake of performance, this recursion is written out manually to make
* it a relation on `Class x Node` rather than `Node x Node` or `MemberFunction
* x Node`, both of which would be larger. It's a forward search since there
* should usually be fewer classes than calls.
*
* If a value is cast several classes up in the hierarchy, that will be modeled
* as a chain of `ConvertToBaseInstruction`s and will cause the search to start
* from each of them and pass through subsequent ones. There might be
* performance to gain by stopping before a second upcast and reconstructing
* the full chain in a "big-step" recursion after this one.
*/
private predicate nodeMayHaveClass(Class derived, DataFlow::Node node) {
exists(ConvertToBaseInstruction toBase |
derived = toBase.getDerivedClass() and
overrideMayAffectCall(derived, _, toBase.getEnclosingFunction(), _, _) and
node.asInstruction() = toBase
)
or
exists(DataFlow::Node prev |
nodeMayHaveClass(derived, prev) and
DataFlow::localFlowStep(prev, node)
)
}
/**

View File

@@ -205,7 +205,8 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
iTo.(CopyInstruction).getSourceValue() = iFrom or
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or
// Treat all conversions as flow, even conversions between different numeric types.
iTo.(ConvertInstruction).getUnary() = iFrom
iTo.(ConvertInstruction).getUnary() = iFrom or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
}
/**
@@ -214,6 +215,14 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
*/
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
/**
* Holds if data can flow from `i1` to `i2` in zero or more
* local (intra-procedural) steps.
*/
predicate localInstructionFlow(Instruction e1, Instruction e2) {
localFlow(instructionNode(e1), instructionNode(e2))
}
/**
* Holds if data can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps.

View File

@@ -53,6 +53,14 @@ private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction no
*/
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
/**
* Holds if taint can flow from `i1` to `i2` in zero or more
* local (intra-procedural) steps.
*/
predicate localInstructionTaint(Instruction i1, Instruction i2) {
localTaint(DataFlow::instructionNode(i1), DataFlow::instructionNode(i2))
}
/**
* Holds if taint can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps.

View File

@@ -4,6 +4,7 @@
private import internal.IRTypeInternal
cached
private newtype TIRType =
TIRVoidType() or
TIRUnknownType() or
@@ -42,6 +43,10 @@ class IRType extends TIRType {
*
* This will hold for all `IRType` objects except `IRUnknownType`.
*/
// This predicate is overridden with `pragma[noinline]` in every leaf subclass.
// This allows callers to ask for things like _the_ floating-point type of
// size 4 without getting a join that first finds all types of size 4 and
// _then_ restricts them to floating-point types.
int getByteSize() { none() }
/**
@@ -104,8 +109,6 @@ private class IRSizedType extends IRType {
this = TIRFunctionAddressType(byteSize) or
this = TIROpaqueType(_, byteSize)
}
final override int getByteSize() { result = byteSize }
}
/**
@@ -117,6 +120,9 @@ class IRBooleanType extends IRSizedType, TIRBooleanType {
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalBooleanType(byteSize)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
}
/**
@@ -141,6 +147,9 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalSignedIntegerType(byteSize)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
}
/**
@@ -153,6 +162,9 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalUnsignedIntegerType(byteSize)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
}
/**
@@ -164,6 +176,9 @@ class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalFloatingPointType(byteSize)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
}
/**
@@ -178,6 +193,9 @@ class IRAddressType extends IRSizedType, TIRAddressType {
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalAddressType(byteSize)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
}
/**
@@ -190,6 +208,9 @@ class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType {
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalFunctionAddressType(byteSize)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
}
/**
@@ -218,6 +239,9 @@ class IROpaqueType extends IRSizedType, TIROpaqueType {
* same size.
*/
final Language::OpaqueTypeTag getTag() { result = tag }
pragma[noinline]
final override int getByteSize() { result = byteSize }
}
module IRTypeSanity {

View File

@@ -34,7 +34,7 @@ private newtype TOpcode =
TPointerSub() or
TPointerDiff() or
TConvert() or
TConvertToBase() or
TConvertToNonVirtualBase() or
TConvertToVirtualBase() or
TConvertToDerived() or
TCheckedConvertOrNull() or
@@ -110,6 +110,8 @@ abstract class RelationalOpcode extends CompareOpcode { }
abstract class CopyOpcode extends Opcode { }
abstract class ConvertToBaseOpcode extends UnaryOpcode { }
abstract class MemoryAccessOpcode extends Opcode { }
abstract class ReturnOpcode extends Opcode { }
@@ -302,11 +304,11 @@ module Opcode {
final override string toString() { result = "Convert" }
}
class ConvertToBase extends UnaryOpcode, TConvertToBase {
final override string toString() { result = "ConvertToBase" }
class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase {
final override string toString() { result = "ConvertToNonVirtualBase" }
}
class ConvertToVirtualBase extends UnaryOpcode, TConvertToVirtualBase {
class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase {
final override string toString() { result = "ConvertToVirtualBase" }
}

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {
@@ -983,14 +981,22 @@ class InheritanceConversionInstruction extends UnaryInstruction {
* to the address of a direct non-virtual base class.
*/
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
ConvertToBaseInstruction() { getOpcode() instanceof Opcode::ConvertToBase }
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
}
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a direct non-virtual base class.
*/
class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction {
ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase }
}
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a virtual base class.
*/
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction {
ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase }
}

View File

@@ -109,7 +109,7 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
instr = operand.getUse() and
(
// Converting to a non-virtual base class adds the offset of the base class.
exists(ConvertToBaseInstruction convert |
exists(ConvertToNonVirtualBaseInstruction convert |
convert = instr and
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
)
@@ -308,6 +308,10 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
instr.(VariableAddressInstruction).getIRVariable() = var and
bitOffset = 0
or
// A string literal is just a special read-only global variable.
instr.(StringConstantInstruction).getIRVariable() = var and
bitOffset = 0
or
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
operand = instr.getAnOperand() and
// If an operand is propagated, then the result points to the same variable,

View File

@@ -210,17 +210,21 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
def instanceof UnknownVirtualVariable and
result instanceof MustTotallyOverlap
or
// An UnknownMemoryLocation may partially overlap any Location within the same virtual variable.
// An UnknownMemoryLocation may partially overlap any Location within the same virtual variable,
// unless the location is read-only.
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof UnknownMemoryLocation and
result instanceof MayPartiallyOverlap
result instanceof MayPartiallyOverlap and
not use.(VariableMemoryLocation).getVariable().isReadOnly()
or
// An UnknownNonLocalMemoryLocation may partially overlap any location within the same virtual
// variable, except a local variable.
// variable, except a local variable or read-only variable.
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof UnknownNonLocalMemoryLocation and
result instanceof MayPartiallyOverlap and
not use.(VariableMemoryLocation).getVariable() instanceof IRAutomaticVariable
not exists(IRVariable var | var = use.(VariableMemoryLocation).getVariable() |
var instanceof IRAutomaticVariable or var.isReadOnly()
)
or
exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and

View File

@@ -341,11 +341,6 @@ private module Cached {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)

View File

@@ -9,4 +9,10 @@ newtype TIRVariable =
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
Construction::hasTempVariable(func, ast, tag, type)
} or
TIRStringLiteral(
Language::Function func, Language::AST ast, Language::LanguageType type,
Language::StringLiteral literal
) {
Construction::hasStringLiteral(func, ast, type, literal)
}

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {
@@ -983,14 +981,22 @@ class InheritanceConversionInstruction extends UnaryInstruction {
* to the address of a direct non-virtual base class.
*/
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
ConvertToBaseInstruction() { getOpcode() instanceof Opcode::ConvertToBase }
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
}
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a direct non-virtual base class.
*/
class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction {
ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase }
}
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a virtual base class.
*/
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction {
ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase }
}

View File

@@ -44,6 +44,13 @@ private module Cached {
)
}
cached
predicate hasStringLiteral(Function func, Locatable ast, CppType type, StringLiteral literal) {
literal = ast and
literal.getEnclosingFunction() = func and
getTypeForPRValue(literal.getType()) = type
}
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
@@ -51,20 +58,23 @@ private module Cached {
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
translatedExpr = getTranslatedExpr(result) and
instruction = translatedExpr.getResult()
instruction = translatedExpr.getResult() and
// Only associate `instruction` with this expression if the translated
// expression actually produced the instruction; not if it merely
// forwarded the result of another translated expression.
instruction = translatedExpr.getInstruction(_)
)
}
cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
exists(Expr converted, TranslatedExpr translatedExpr |
exists(Expr converted |
result = converted.(Conversion).getExpr+()
or
result = converted
|
not result instanceof Conversion and
translatedExpr = getTranslatedExpr(converted) and
instruction = translatedExpr.getResult()
converted = getInstructionConvertedResultExpression(instruction)
)
}
@@ -231,8 +241,14 @@ private module Cached {
cached
IRVariable getInstructionVariable(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)
.getInstructionVariable(getInstructionTag(instruction))
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
(
result = element.getInstructionVariable(tag) or
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
)
)
}
cached
@@ -263,12 +279,6 @@ private module Cached {
)
}
cached
StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)
.getInstructionStringLiteral(getInstructionTag(instruction))
}
cached
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)

View File

@@ -45,6 +45,7 @@ newtype TInstructionTag =
ConditionValueResultLoadTag() or
BoolConversionConstantTag() or
BoolConversionCompareTag() or
ResultCopyTag() or
LoadTag() or // Implicit load due to lvalue-to-rvalue conversion
CatchTag() or
ThrowTag() or

View File

@@ -120,7 +120,8 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
private predicate hasUninitializedInstruction() {
not exists(getInitialization()) or
getInitialization() instanceof TranslatedListInitialization
getInitialization() instanceof TranslatedListInitialization or
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
}
}

View File

@@ -9,6 +9,7 @@ private import InstructionTag
private import TranslatedCondition
private import TranslatedFunction
private import TranslatedStmt
private import TranslatedExpr
private import IRConstruction
private import semmle.code.cpp.models.interfaces.SideEffect
@@ -235,6 +236,15 @@ newtype TTranslatedElement =
expr.hasLValueToRValueConversion() and
not ignoreLoad(expr)
} or
TTranslatedResultCopy(Expr expr) {
not ignoreExpr(expr) and
exprNeedsCopyIfNotLoaded(expr) and
// Doesn't have a TTranslatedLoad
not (
expr.hasLValueToRValueConversion() and
not ignoreLoad(expr)
)
} or
// An expression most naturally translated as control flow.
TTranslatedNativeCondition(Expr expr) {
not ignoreExpr(expr) and

View File

@@ -62,12 +62,11 @@ abstract class TranslatedExpr extends TranslatedElement {
/**
* Holds if the result of this `TranslatedExpr` is a glvalue.
*/
private predicate isResultGLValue() {
predicate isResultGLValue() {
// This implementation is overridden in `TranslatedCoreExpr` to mark them
// as glvalues if they have loads on them. It's not overridden in
// `TranslatedResultCopy` since result copies never have loads.
expr.isGLValueCategory()
or
// If this TranslatedExpr doesn't produce the result, then it must represent
// a glvalue that is then loaded by a TranslatedLoad.
not producesExprResult()
}
final override Locatable getAST() { result = expr }
@@ -96,14 +95,28 @@ abstract class TranslatedExpr extends TranslatedElement {
abstract class TranslatedCoreExpr extends TranslatedExpr {
final override string toString() { result = expr.toString() }
/**
* Holds if the result of this `TranslatedExpr` is a glvalue.
*/
override predicate isResultGLValue() {
super.isResultGLValue()
or
// If this TranslatedExpr doesn't produce the result, then it must represent
// a glvalue that is then loaded by a TranslatedLoad.
hasLoad()
}
final predicate hasLoad() {
expr.hasLValueToRValueConversion() and
not ignoreLoad(expr)
}
final override predicate producesExprResult() {
// If there's no load, then this is the only TranslatedExpr for this
// expression.
not expr.hasLValueToRValueConversion()
or
// If we're supposed to ignore the load on this expression, then this
// is the only TranslatedExpr.
ignoreLoad(expr)
not hasLoad() and
// If there's a result copy, then this expression's result is the copy.
not exprNeedsCopyIfNotLoaded(expr)
}
}
@@ -288,6 +301,48 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
private TranslatedCoreExpr getOperand() { result.getExpr() = expr }
}
/**
* IR translation of an implicit lvalue-to-rvalue conversion on the result of
* an expression.
*/
class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy {
TranslatedResultCopy() { this = TTranslatedResultCopy(expr) }
override string toString() { result = "Result of " + expr.toString() }
override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() }
override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = ResultCopyTag() and
opcode instanceof Opcode::CopyValue and
resultType = getOperand().getResultType()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = ResultCopyTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getOperand() and result = getInstruction(ResultCopyTag())
}
override Instruction getResult() { result = getInstruction(ResultCopyTag()) }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = ResultCopyTag() and
operandTag instanceof UnaryOperandTag and
result = getOperand().getResult()
}
final override predicate producesExprResult() { any() }
private TranslatedCoreExpr getOperand() { result.getExpr() = expr }
}
class TranslatedCommaExpr extends TranslatedNonConstantExpr {
override CommaExpr expr;
@@ -983,7 +1038,7 @@ class TranslatedInheritanceConversion extends TranslatedSingleInstructionConvers
then
if expr.(BaseClassConversion).isVirtual()
then result instanceof Opcode::ConvertToVirtualBase
else result instanceof Opcode::ConvertToBase
else result instanceof Opcode::ConvertToNonVirtualBase
else result instanceof Opcode::ConvertToDerived
}
}
@@ -2403,6 +2458,58 @@ class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
final override Opcode getOpcode() { result instanceof Opcode::Error }
}
/**
* Holds if the translation of `expr` will not directly generate any
* `Instruction` for use as result. For such instructions we can synthesize a
* `CopyValue` instruction to ensure that there is a 1-to-1 mapping between
* expressions and result-bearing instructions.
*/
// This should ideally be a dispatch predicate on TranslatedNonConstantExpr,
// but it doesn't look monotonic to QL.
predicate exprNeedsCopyIfNotLoaded(Expr expr) {
(
expr instanceof AssignExpr
or
expr instanceof AssignOperation and
not expr.isPRValueCategory() // is C++
or
expr instanceof PrefixCrementOperation and
not expr.isPRValueCategory() // is C++
or
expr instanceof PointerDereferenceExpr
or
expr instanceof AddressOfExpr
or
expr instanceof BuiltInOperationBuiltInAddressOf
or
// No case for ParenthesisExpr to avoid getting too many instructions
expr instanceof ReferenceDereferenceExpr
or
expr instanceof ReferenceToExpr
or
expr instanceof CommaExpr
or
expr instanceof ConditionDeclExpr
// TODO: simplify TranslatedStmtExpr too
) and
not exprImmediatelyDiscarded(expr)
}
/**
* Holds if `expr` is immediately discarded. Such expressions do not need a
* `CopyValue` because it's unlikely that anyone is interested in their value.
*/
private predicate exprImmediatelyDiscarded(Expr expr) {
exists(ExprStmt s |
s = expr.getParent() and
not exists(StmtExpr se | s = se.getStmt().(Block).getLastStmt())
)
or
exists(CommaExpr c | c.getLeftOperand() = expr)
or
exists(ForStmt for | for.getUpdate() = expr)
}
/**
* The IR translation of an `__assume` expression. We currently translate these as `NoOp`. In the
* future, we will probably want to do something better. At a minimum, we can model `__assume(0)` as

View File

@@ -340,7 +340,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
* Holds if the `elementCount` array elements starting at `startIndex` must be
* zero initialized.
*/
private predicate zeroInitRange(int startIndex, int elementCount) {
predicate zeroInitRange(int startIndex, int elementCount) {
exists(int targetCount |
startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and
targetCount = getContext().getTargetType().getUnspecifiedType().(ArrayType).getArraySize() and
@@ -752,7 +752,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = OnlyInstructionTag() and
opcode instanceof Opcode::ConvertToBase and
opcode instanceof Opcode::ConvertToNonVirtualBase and
resultType = getTypeForGLValue(call.getTarget().getDeclaringType())
}

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {
@@ -983,14 +981,22 @@ class InheritanceConversionInstruction extends UnaryInstruction {
* to the address of a direct non-virtual base class.
*/
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
ConvertToBaseInstruction() { getOpcode() instanceof Opcode::ConvertToBase }
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
}
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a direct non-virtual base class.
*/
class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction {
ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase }
}
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a virtual base class.
*/
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction {
ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase }
}

View File

@@ -109,7 +109,7 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
instr = operand.getUse() and
(
// Converting to a non-virtual base class adds the offset of the base class.
exists(ConvertToBaseInstruction convert |
exists(ConvertToNonVirtualBaseInstruction convert |
convert = instr and
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
)
@@ -308,6 +308,10 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
instr.(VariableAddressInstruction).getIRVariable() = var and
bitOffset = 0
or
// A string literal is just a special read-only global variable.
instr.(StringConstantInstruction).getIRVariable() = var and
bitOffset = 0
or
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
operand = instr.getAnOperand() and
// If an operand is propagated, then the result points to the same variable,

View File

@@ -341,11 +341,6 @@ private module Cached {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)

View File

@@ -175,6 +175,7 @@ private IRType getIRTypeForPRValue(Type type) {
)
}
cached
private newtype TCppType =
TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or
TFunctionGLValueType() or
@@ -203,6 +204,7 @@ class CppType extends TCppType {
* Gets the `IRType` that represents this `CppType`. Many different `CppType`s can map to a single
* `IRType`.
*/
cached
IRType getIRType() { none() }
/**

View File

@@ -3,7 +3,7 @@ import semmle.code.cpp.dataflow.DataFlow
module BoostorgAsio {
/**
* Represents boost::asio::ssl::context enum
* Represents the `boost::asio::ssl::context` enum.
*/
class SslContextMethod extends Enum {
SslContextMethod() {
@@ -12,7 +12,7 @@ module BoostorgAsio {
}
/**
* returns the value for a banned protocol
* Gets an enumeration constant for a banned protocol.
*/
EnumConstant getABannedProtocolConstant() {
result = this.getAnEnumConstant() and
@@ -56,14 +56,15 @@ module BoostorgAsio {
}
/**
* returns the value for a approved protocols, but that are hard-coded (i.e. no protocol negotiation)
* Gets an enumeration constant for an approved protocol, that is hard-coded
* (no protocol negotiation).
*/
EnumConstant getAnApprovedButHardcodedProtocolConstant() {
result = this.getATls12ProtocolConstant()
}
/**
* returns the value for a TLS v1.2 protocol
* Gets an enumeration constant for a TLS v1.2 protocol.
*/
EnumConstant getATls12ProtocolConstant() {
result = this.getAnEnumConstant() and
@@ -80,7 +81,7 @@ module BoostorgAsio {
}
/**
* returns the value for a TLS v1.3 protocol
* Gets an enumeration constant for a TLS v1.3 protocol.
*/
EnumConstant getATls13ProtocolConstant() {
result = this.getAnEnumConstant() and
@@ -97,7 +98,7 @@ module BoostorgAsio {
}
/**
* returns the value of a generic TLS or SSL/TLS protocol
* Gets an enumeration constant for a generic TLS or SSL/TLS protocol.
*/
EnumConstant getAGenericTlsProtocolConstant() {
result = this.getAnEnumConstant() and
@@ -116,7 +117,7 @@ module BoostorgAsio {
}
/**
* returns the value of a generic SSL/TLS protocol
* Gets an enumeration constant for a generic SSL/TLS protocol.
*/
EnumConstant getASslv23ProtocolConstant() {
result = this.getAnEnumConstant() and
@@ -135,7 +136,9 @@ module BoostorgAsio {
}
/**
* NOTE: ignore - Modern versions of OpenSSL do not support SSL v2 anymore, so this option is for backwards compatibility only
* Gets the value for the no_sslv2 constant, right shifted by 16 bits.
*
* Note that modern versions of OpelSSL do not support SSL v2, so this option is for backwards compatibility only.
*/
int getShiftedSslOptionsNoSsl2() {
// SSL_OP_NO_SSLv2 was removed from modern OpenSSL versions
@@ -143,7 +146,7 @@ module BoostorgAsio {
}
/**
* RightShift(16) value for no_sslv3 constant
* Gets the value for the no_sslv3 constant, right shifted by 16 bits.
*/
int getShiftedSslOptionsNoSsl3() {
// SSL_OP_NO_SSLv3 == 0x02000000U
@@ -151,7 +154,7 @@ module BoostorgAsio {
}
/**
* RightShift(16) value for no_tlsv1 constant
* Gets the value for the no_tlsv1 constant, right shifted by 16 bits.
*/
int getShiftedSslOptionsNoTls1() {
// SSL_OP_NO_TLSv1 == 0x04000000U
@@ -159,7 +162,7 @@ module BoostorgAsio {
}
/**
* RightShift(16) value for no_tlsv1_1 constant
* Gets the value for the no_tlsv1_1 constant, right shifted by 16 bits.
*/
int getShiftedSslOptionsNoTls1_1() {
// SSL_OP_NO_TLSv1_1 == 0x10000000U
@@ -167,7 +170,7 @@ module BoostorgAsio {
}
/**
* RightShift(16) value for no_tlsv1_2 constant
* Gets the value for the no_tlsv1_2 constant, right shifted by 16 bits.
*/
int getShiftedSslOptionsNoTls1_2() {
// SSL_OP_NO_TLSv1_2 == 0x08000000U
@@ -175,7 +178,7 @@ module BoostorgAsio {
}
/**
* RightShift(16) value for no_tlsv1_3 constant
* Gets the value for the no_tlsv1_3 constant, right shifted by 16 bits.
*/
int getShiftedSslOptionsNoTls1_3() {
// SSL_OP_NO_TLSv1_2 == 0x20000000U
@@ -183,7 +186,7 @@ module BoostorgAsio {
}
/**
* Represents boost::asio::ssl::context class
* Represents the `boost::asio::ssl::context` class.
*/
class SslContextClass extends Class {
SslContextClass() { this.getQualifiedName() = "boost::asio::ssl::context" }
@@ -196,7 +199,7 @@ module BoostorgAsio {
}
/**
* Represents boost::asio::ssl::context::set_options member function
* Represents `boost::asio::ssl::context::set_options` member function.
*/
class SslSetOptionsFunction extends Function {
SslSetOptionsFunction() {
@@ -205,7 +208,7 @@ module BoostorgAsio {
}
/**
* holds if the expression represents a banned protocol
* Holds if the expression represents a banned protocol.
*/
predicate isExprBannedBoostProtocol(Expr e) {
exists(Literal va | va = e |
@@ -244,7 +247,7 @@ module BoostorgAsio {
}
/**
* holds if the expression represents a TLS v1.2 protocol
* Holds if the expression represents a TLS v1.2 protocol.
*/
predicate isExprTls12BoostProtocol(Expr e) {
exists(Literal va | va = e |
@@ -269,7 +272,7 @@ module BoostorgAsio {
}
/**
* holds if the expression represents a protocol that requires Crypto Board approval
* Holds if the expression represents a protocol that requires Crypto Board approval.
*/
predicate isExprTls13BoostProtocol(Expr e) {
exists(Literal va | va = e |
@@ -294,7 +297,7 @@ module BoostorgAsio {
}
/**
* holds if the expression represents a generic TLS or SSL/TLS protocol
* Holds if the expression represents a generic TLS or SSL/TLS protocol.
*/
predicate isExprTlsBoostProtocol(Expr e) {
exists(Literal va | va = e |
@@ -325,7 +328,7 @@ module BoostorgAsio {
}
/**
* holds if the expression represents a generic SSl/TLS protocol
* Holds if the expression represents a generic SSl/TLS protocol.
*/
predicate isExprSslV23BoostProtocol(Expr e) {
exists(Literal va | va = e |
@@ -351,7 +354,8 @@ module BoostorgAsio {
//////////////////////// Dataflow /////////////////////
/**
* Abstract - Protocol value Flows to the first argument of the context constructor
* Abstract class for flows of protocol values to the first argument of a context
* constructor.
*/
abstract class SslContextCallAbstractConfig extends DataFlow::Configuration {
bindingset[this]
@@ -366,7 +370,7 @@ module BoostorgAsio {
}
/**
* any Protocol value Flows to the first argument of the context constructor
* Any protocol value that flows to the first argument of a context constructor.
*/
class SslContextCallConfig extends SslContextCallAbstractConfig {
SslContextCallConfig() { this = "SslContextCallConfig" }
@@ -380,7 +384,7 @@ module BoostorgAsio {
}
/**
* a banned protocol value Flows to the first argument of the context constructor
* A banned protocol value that flows to the first argument of a context constructor.
*/
class SslContextCallBannedProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallBannedProtocolConfig() { this = "SslContextCallBannedProtocolConfig" }
@@ -395,7 +399,7 @@ module BoostorgAsio {
}
/**
* a TLS 1.2 protocol value Flows to the first argument of the context constructor
* A TLS 1.2 protocol value that flows to the first argument of a context constructor.
*/
class SslContextCallTls12ProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTls12ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" }
@@ -410,7 +414,7 @@ module BoostorgAsio {
}
/**
* a TLS 1.3 protocol value Flows to the first argument of the context constructor
* A TLS 1.3 protocol value that flows to the first argument of a context constructor.
*/
class SslContextCallTls13ProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTls13ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" }
@@ -425,7 +429,7 @@ module BoostorgAsio {
}
/**
* a generic TLS protocol value Flows to the first argument of the context constructor
* A generic TLS protocol value that flows to the first argument of a context constructor.
*/
class SslContextCallTlsProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTlsProtocolConfig() { this = "SslContextCallTlsProtocolConfig" }
@@ -440,7 +444,7 @@ module BoostorgAsio {
}
/**
* a context constructor call flows to a call calling SetOptions()
* A context constructor call that flows to a call to `SetOptions()`.
*/
class SslContextFlowsToSetOptionConfig extends DataFlow::Configuration {
SslContextFlowsToSetOptionConfig() { this = "SslContextFlowsToSetOptionConfig" }
@@ -464,7 +468,7 @@ module BoostorgAsio {
}
/**
* an option value flows to the 1st parameter of SetOptions()
* An option value that flows to the first parameter of a call to `SetOptions()`.
*/
class SslOptionConfig extends DataFlow::Configuration {
SslOptionConfig() { this = "SslOptionConfig" }

View File

@@ -731,6 +731,11 @@ class_template_argument(
int index: int ref,
int arg_type: @type ref
);
class_template_argument_value(
int type_id: @usertype ref,
int index: int ref,
int arg_value: @expr ref
);
is_proxy_class_for(
unique int id: @usertype ref,
@@ -755,6 +760,11 @@ function_template_argument(
int index: int ref,
int arg_type: @type ref
);
function_template_argument_value(
int function_id: @function ref,
int index: int ref,
int arg_value: @expr ref
);
is_variable_template(unique int id: @variable ref);
variable_instantiation(
@@ -766,6 +776,11 @@ variable_template_argument(
int index: int ref,
int arg_type: @type ref
);
variable_template_argument_value(
int variable_id: @variable ref,
int index: int ref,
int arg_value: @expr ref
);
/*
Fixed point types

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
int source();
void sink(int);
// This class has the opposite behavior of what the member function names suggest.
struct Top {
virtual int isSource1() { return 0; }
virtual int isSource2() { return 0; }
virtual void isSink(int x) { }
virtual int notSource1() { return source(); }
virtual int notSource2() { return source(); }
virtual void notSink(int x) { sink(x); }
};
// This class has the correct behavior for just the functions ending in 2.
struct Middle : Top {
int isSource2() override { return source(); }
int notSource2() override { return 0; }
};
// This class has all the behavior suggested by the function names.
struct Bottom : Middle {
int isSource1() override { return source(); }
void isSink(int x) override { sink(x); }
int notSource1() override { return 0; }
void notSink(int x) override { }
};
void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) {
Top *topPtr = bottomPtr, &topRef = bottomRef;
sink(topPtr->isSource1()); // flow [NOT DETECTED by AST]
sink(topPtr->isSource2()); // flow [NOT DETECTED by AST]
topPtr->isSink(source()); // flow [NOT DETECTED by AST]
sink(topPtr->notSource1()); // no flow [FALSE POSITIVE]
sink(topPtr->notSource2()); // no flow [FALSE POSITIVE]
topPtr->notSink(source()); // no flow [FALSE POSITIVE]
sink(topRef.isSource1()); // flow [NOT DETECTED by AST]
sink(topRef.isSource2()); // flow [NOT DETECTED by AST]
topRef.isSink(source()); // flow [NOT DETECTED by AST]
sink(topRef.notSource1()); // no flow [FALSE POSITIVE]
sink(topRef.notSource2()); // no flow [FALSE POSITIVE]
topRef.notSink(source()); // no flow [FALSE POSITIVE]
}

View File

@@ -15,6 +15,12 @@
| clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source |
| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
| dispatch.cpp:11:38:11:38 | x | dispatch.cpp:37:19:37:24 | call to source |
| dispatch.cpp:11:38:11:38 | x | dispatch.cpp:45:18:45:23 | call to source |
| dispatch.cpp:35:16:35:25 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source |
| dispatch.cpp:36:16:36:25 | call to notSource2 | dispatch.cpp:10:37:10:42 | call to source |
| dispatch.cpp:43:15:43:24 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source |
| dispatch.cpp:44:15:44:24 | call to notSource2 | dispatch.cpp:10:37:10:42 | call to source |
| lambdas.cpp:14:3:14:6 | t | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:18:8:18:8 | call to operator() | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:21:3:21:6 | t | lambdas.cpp:8:10:8:15 | call to source |

View File

@@ -5,6 +5,12 @@
| clang.cpp:28:27:28:32 | clang.cpp:29:27:29:28 | AST only |
| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only |
| clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only |
| dispatch.cpp:22:37:22:42 | dispatch.cpp:31:16:31:24 | IR only |
| dispatch.cpp:22:37:22:42 | dispatch.cpp:39:15:39:23 | IR only |
| dispatch.cpp:33:18:33:23 | dispatch.cpp:23:38:23:38 | IR only |
| dispatch.cpp:41:17:41:22 | dispatch.cpp:23:38:23:38 | IR only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |

View File

@@ -12,6 +12,18 @@
| clang.cpp:37:10:37:11 | Load: m2 | clang.cpp:34:32:34:37 | Call: call to source |
| clang.cpp:41:18:41:19 | Load: m2 | clang.cpp:39:42:39:47 | Call: call to source |
| clang.cpp:45:17:45:18 | Load: m2 | clang.cpp:43:35:43:40 | Call: call to source |
| dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:37:19:37:24 | Call: call to source |
| dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:45:18:45:23 | Call: call to source |
| dispatch.cpp:23:38:23:38 | Load: x | dispatch.cpp:33:18:33:23 | Call: call to source |
| dispatch.cpp:23:38:23:38 | Load: x | dispatch.cpp:41:17:41:22 | Call: call to source |
| dispatch.cpp:31:16:31:24 | Call: call to isSource1 | dispatch.cpp:22:37:22:42 | Call: call to source |
| dispatch.cpp:32:16:32:24 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source |
| dispatch.cpp:35:16:35:25 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source |
| dispatch.cpp:36:16:36:25 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source |
| dispatch.cpp:39:15:39:23 | Call: call to isSource1 | dispatch.cpp:22:37:22:42 | Call: call to source |
| dispatch.cpp:40:15:40:23 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source |
| dispatch.cpp:43:15:43:24 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source |
| dispatch.cpp:44:15:44:24 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source |
| test.cpp:7:8:7:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:9:8:9:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:10:8:10:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source |

View File

@@ -1,6 +1,16 @@
| escape.cpp:111:18:111:21 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0:0 | no_+0:0 |
| escape.cpp:115:20:115:23 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:116:19:116:28 | PointerSub[4] | no_+0:0 | no_+0:0 |
| escape.cpp:116:20:116:23 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0:0 | no_+0:0 |
| escape.cpp:117:23:117:26 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:118:9:118:12 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:120:12:120:15 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:123:14:123:17 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:124:15:124:18 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:127:9:127:12 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:129:12:129:15 | CopyValue | no_+0:0 | no_+0:0 |
| escape.cpp:134:5:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
| escape.cpp:134:11:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
| escape.cpp:135:5:135:12 | Convert | no_Array+0:0 | no_Array+0:0 |
@@ -16,32 +26,61 @@
| escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
| escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 |
| escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
| escape.cpp:143:19:143:27 | CopyValue | no_Point+0:0 | no_Point+0:0 |
| escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
| escape.cpp:144:6:144:14 | CopyValue | no_Point+0:0 | no_Point+0:0 |
| escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
| escape.cpp:145:20:145:30 | CopyValue | no_Point+8:0 | no_Point+8:0 |
| escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
| escape.cpp:146:5:146:18 | CopyValue | no_Point+8:0 | no_Point+8:0 |
| escape.cpp:146:7:146:17 | CopyValue | no_Point+8:0 | no_Point+8:0 |
| escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
| escape.cpp:149:5:149:14 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:149:5:149:14 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:149:16:149:16 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:150:18:150:27 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:150:18:150:27 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:150:29:150:29 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 |
| escape.cpp:151:5:151:14 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
| escape.cpp:151:5:151:14 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
| escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
| escape.cpp:152:19:152:28 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
| escape.cpp:152:19:152:28 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
| escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
| escape.cpp:155:17:155:30 | CopyValue | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 |
| escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 |
| escape.cpp:158:17:158:28 | CopyValue | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 |
| escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 |
| escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0:0 | no_ssa_refToArrayElement+0:0 |
| escape.cpp:161:19:161:45 | CopyValue | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
| escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
| escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
| escape.cpp:164:24:164:40 | CopyValue | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 |
| escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 |
| escape.cpp:167:19:167:28 | CopyValue | passByPtr+0:0 | passByPtr+0:0 |
| escape.cpp:170:21:170:29 | CopyValue | passByRef+0:0 | passByRef+0:0 |
| escape.cpp:173:22:173:38 | CopyValue | no_ssa_passByPtr+0:0 | no_ssa_passByPtr+0:0 |
| escape.cpp:176:24:176:39 | CopyValue | no_ssa_passByRef+0:0 | no_ssa_passByRef+0:0 |
| escape.cpp:179:22:179:42 | CopyValue | no_ssa_passByPtr_ret+0:0 | no_ssa_passByPtr_ret+0:0 |
| escape.cpp:182:24:182:43 | CopyValue | no_ssa_passByRef_ret+0:0 | no_ssa_passByRef_ret+0:0 |
| escape.cpp:185:30:185:40 | CopyValue | passByPtr2+0:0 | passByPtr2+0:0 |
| escape.cpp:188:32:188:41 | CopyValue | passByRef2+0:0 | passByRef2+0:0 |
| escape.cpp:191:30:191:42 | Call | none | passByPtr3+0:0 |
| escape.cpp:191:44:191:54 | CopyValue | passByPtr3+0:0 | passByPtr3+0:0 |
| escape.cpp:194:32:194:46 | Call | none | passByRef3+0:0 |
| escape.cpp:194:32:194:59 | CopyValue | none | passByRef3+0:0 |
| escape.cpp:194:48:194:57 | CopyValue | passByRef3+0:0 | passByRef3+0:0 |
| escape.cpp:199:17:199:34 | CopyValue | no_ssa_passByPtr4+0:0 | no_ssa_passByPtr4+0:0 |
| escape.cpp:199:37:199:54 | CopyValue | no_ssa_passByPtr5+0:0 | no_ssa_passByPtr5+0:0 |
| escape.cpp:202:5:202:19 | Call | none | passByRef6+0:0 |
| escape.cpp:202:5:202:32 | CopyValue | none | passByRef6+0:0 |
| escape.cpp:202:21:202:30 | CopyValue | passByRef6+0:0 | passByRef6+0:0 |
| escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0:0 |
| escape.cpp:205:5:205:39 | CopyValue | none | no_ssa_passByRef7+0:0 |
| escape.cpp:205:21:205:37 | CopyValue | no_ssa_passByRef7+0:0 | no_ssa_passByRef7+0:0 |
| escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0:0 |
| escape.cpp:217:14:217:16 | CopyValue | c2+0:0 | c2+0:0 |
| escape.cpp:221:8:221:19 | Call | none | c3+0:0 |
| escape.cpp:225:17:225:28 | Call | none | c4+0:0 |
| escape.cpp:247:2:247:27 | Store | condEscape1+0:0 | condEscape1+0:0 |
| escape.cpp:247:16:247:27 | CopyValue | condEscape1+0:0 | condEscape1+0:0 |
| escape.cpp:249:9:249:34 | Store | condEscape2+0:0 | condEscape2+0:0 |
| escape.cpp:249:23:249:34 | CopyValue | condEscape2+0:0 | condEscape2+0:0 |

View File

@@ -67,31 +67,7 @@ bad_asts.cpp:
# 5| params:
#-----| 0: [Parameter] p#0
#-----| Type = [RValueReferenceType] S &&
# 9| [MemberFunction] int Bad::S::MemberFunction(int)
# 9| params:
# 9| 0: [Parameter] y
# 9| Type = [IntType] int
# 9| body: [Block] { ... }
# 10| 0: [ReturnStmt] return ...
# 10| 0: [AddExpr] ... + ...
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue
# 10| 0: [AddExpr] ... + ...
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue
# 10| 0: [Literal] Unknown literal
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue
# 10| 1: [PointerFieldAccess] x
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue(load)
#-----| -1: [ThisExpr] this
#-----| Type = [PointerType] S *
#-----| ValueCategory = prvalue(load)
# 10| 1: [VariableAccess] y
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue(load)
# 9| [TopLevelFunction] int MemberFunction(int)
# 9| [FunctionTemplateInstantiation,MemberFunction] int Bad::S::MemberFunction<int 6>(int)
# 9| params:
# 9| 0: [Parameter] y
# 9| Type = [IntType] int
@@ -116,6 +92,31 @@ bad_asts.cpp:
# 10| 1: [VariableAccess] y
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue(load)
# 9| [MemberFunction,TemplateFunction] int Bad::S::MemberFunction<int t>(int)
# 9| params:
# 9| 0: [Parameter] y
# 9| Type = [IntType] int
# 9| body: [Block] { ... }
# 10| 0: [ReturnStmt] return ...
# 10| 0: [AddExpr] ... + ...
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue
# 10| 0: [AddExpr] ... + ...
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue
# 10| 0: [Literal] t
# 10| Type = [IntType] int
# 10| Value = [Literal] t
# 10| ValueCategory = prvalue
# 10| 1: [PointerFieldAccess] x
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue(load)
#-----| -1: [ThisExpr] this
#-----| Type = [PointerType] S *
#-----| ValueCategory = prvalue(load)
# 10| 1: [VariableAccess] y
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue(load)
# 14| [TopLevelFunction] void Bad::CallBadMemberFunction()
# 14| params:
# 14| body: [Block] { ... }

File diff suppressed because it is too large Load Diff

View File

@@ -215,8 +215,9 @@ ssa.cpp:
# 70| r1_3(int) = Constant[1] :
# 70| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
# 70| m1_5(char *) = Store : &:r1_1, r1_4
# 70| m1_6(char) = Store : &:r1_2, r1_0
# 70| m1_7(unknown) = Chi : total:m3_0, partial:m1_6
# 70| r1_6(glval<char>) = CopyValue : r1_2
# 70| m1_7(char) = Store : &:r1_6, r1_0
# 70| m1_8(unknown) = Chi : total:m3_0, partial:m1_7
#-----| Goto (back edge) -> Block 3
# 71| Block 2
@@ -227,7 +228,7 @@ ssa.cpp:
# 68| v2_4(void) = ExitFunction :
# 69| Block 3
# 69| m3_0(unknown) = Phi : from 0:~m0_1, from 1:~m1_7
# 69| m3_0(unknown) = Phi : from 0:~m0_1, from 1:~m1_8
# 69| m3_1(int) = Phi : from 0:m0_4, from 1:m3_7
# 69| m3_2(char *) = Phi : from 0:m0_6, from 1:m1_5
# 69| r3_3(glval<int>) = VariableAddress[n] :
@@ -330,18 +331,19 @@ ssa.cpp:
# 96| m0_9(Point) = Store : &:r0_6, r0_8
# 97| r0_10(glval<unknown>) = FunctionAddress[Escape] :
# 97| r0_11(glval<Point>) = VariableAddress[a] :
# 97| r0_12(void *) = Convert : r0_11
# 97| v0_13(void) = Call : func:r0_10, 0:r0_12
# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5
# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14
# 97| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_12, ~m0_15
# 97| m0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12
# 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17
# 98| v0_19(void) = NoOp :
# 95| v0_20(void) = ReturnVoid :
# 95| v0_21(void) = UnmodeledUse : mu*
# 95| v0_22(void) = AliasedUse : ~m0_15
# 95| v0_23(void) = ExitFunction :
# 97| r0_12(Point *) = CopyValue : r0_11
# 97| r0_13(void *) = Convert : r0_12
# 97| v0_14(void) = Call : func:r0_10, 0:r0_13
# 97| m0_15(unknown) = ^CallSideEffect : ~m0_5
# 97| m0_16(unknown) = Chi : total:m0_5, partial:m0_15
# 97| v0_17(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m0_16
# 97| m0_18(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13
# 97| m0_19(unknown) = Chi : total:m0_16, partial:m0_18
# 98| v0_20(void) = NoOp :
# 95| v0_21(void) = ReturnVoid :
# 95| v0_22(void) = UnmodeledUse : mu*
# 95| v0_23(void) = AliasedUse : ~m0_16
# 95| v0_24(void) = ExitFunction :
# 100| void MustTotallyOverlap(Point)
# 100| Block 0
@@ -386,18 +388,19 @@ ssa.cpp:
# 107| m0_15(int) = Store : &:r0_11, r0_14
# 108| r0_16(glval<unknown>) = FunctionAddress[Escape] :
# 108| r0_17(glval<Point>) = VariableAddress[a] :
# 108| r0_18(void *) = Convert : r0_17
# 108| v0_19(void) = Call : func:r0_16, 0:r0_18
# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5
# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20
# 108| v0_22(void) = ^BufferReadSideEffect[0] : &:r0_18, ~m0_21
# 108| m0_23(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_18
# 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23
# 109| v0_25(void) = NoOp :
# 105| v0_26(void) = ReturnVoid :
# 105| v0_27(void) = UnmodeledUse : mu*
# 105| v0_28(void) = AliasedUse : ~m0_21
# 105| v0_29(void) = ExitFunction :
# 108| r0_18(Point *) = CopyValue : r0_17
# 108| r0_19(void *) = Convert : r0_18
# 108| v0_20(void) = Call : func:r0_16, 0:r0_19
# 108| m0_21(unknown) = ^CallSideEffect : ~m0_5
# 108| m0_22(unknown) = Chi : total:m0_5, partial:m0_21
# 108| v0_23(void) = ^BufferReadSideEffect[0] : &:r0_19, ~m0_22
# 108| m0_24(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_19
# 108| m0_25(unknown) = Chi : total:m0_22, partial:m0_24
# 109| v0_26(void) = NoOp :
# 105| v0_27(void) = ReturnVoid :
# 105| v0_28(void) = UnmodeledUse : mu*
# 105| v0_29(void) = AliasedUse : ~m0_22
# 105| v0_30(void) = ExitFunction :
# 111| void MayPartiallyOverlap(int, int)
# 111| Block 0
@@ -458,18 +461,19 @@ ssa.cpp:
# 118| m0_23(Point) = Store : &:r0_20, r0_22
# 119| r0_24(glval<unknown>) = FunctionAddress[Escape] :
# 119| r0_25(glval<Point>) = VariableAddress[a] :
# 119| r0_26(void *) = Convert : r0_25
# 119| v0_27(void) = Call : func:r0_24, 0:r0_26
# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19
# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28
# 119| v0_30(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m0_29
# 119| m0_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26
# 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31
# 120| v0_33(void) = NoOp :
# 116| v0_34(void) = ReturnVoid :
# 116| v0_35(void) = UnmodeledUse : mu*
# 116| v0_36(void) = AliasedUse : ~m0_29
# 116| v0_37(void) = ExitFunction :
# 119| r0_26(Point *) = CopyValue : r0_25
# 119| r0_27(void *) = Convert : r0_26
# 119| v0_28(void) = Call : func:r0_24, 0:r0_27
# 119| m0_29(unknown) = ^CallSideEffect : ~m0_19
# 119| m0_30(unknown) = Chi : total:m0_19, partial:m0_29
# 119| v0_31(void) = ^BufferReadSideEffect[0] : &:r0_27, ~m0_30
# 119| m0_32(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_27
# 119| m0_33(unknown) = Chi : total:m0_30, partial:m0_32
# 120| v0_34(void) = NoOp :
# 116| v0_35(void) = ReturnVoid :
# 116| v0_36(void) = UnmodeledUse : mu*
# 116| v0_37(void) = AliasedUse : ~m0_30
# 116| v0_38(void) = ExitFunction :
# 122| void MergeMustExactlyOverlap(bool, int, int)
# 122| Block 0
@@ -773,21 +777,23 @@ ssa.cpp:
# 184| m0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
# 189| r0_11(glval<unsigned int &>) = VariableAddress[a] :
# 189| r0_12(unsigned int &) = Load : &:r0_11, m0_4
# 189| r0_13(glval<unsigned int &>) = VariableAddress[b] :
# 189| r0_14(unsigned int &) = Load : &:r0_13, m0_6
# 190| r0_15(glval<unsigned int &>) = VariableAddress[c] :
# 190| r0_16(unsigned int &) = Load : &:r0_15, m0_8
# 190| r0_17(unsigned int) = Load : &:r0_16, ~m0_1
# 190| r0_18(glval<unsigned int &>) = VariableAddress[d] :
# 190| r0_19(unsigned int &) = Load : &:r0_18, m0_10
# 190| r0_20(unsigned int) = Load : &:r0_19, ~m0_1
# 186| m0_21(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_14, 2:r0_17, 3:r0_20
# 186| m0_22(unknown) = Chi : total:m0_1, partial:m0_21
# 192| v0_23(void) = NoOp :
# 184| v0_24(void) = ReturnVoid :
# 184| v0_25(void) = UnmodeledUse : mu*
# 184| v0_26(void) = AliasedUse : ~m0_22
# 184| v0_27(void) = ExitFunction :
# 189| r0_13(glval<unsigned int>) = CopyValue : r0_12
# 189| r0_14(glval<unsigned int &>) = VariableAddress[b] :
# 189| r0_15(unsigned int &) = Load : &:r0_14, m0_6
# 189| r0_16(glval<unsigned int>) = CopyValue : r0_15
# 190| r0_17(glval<unsigned int &>) = VariableAddress[c] :
# 190| r0_18(unsigned int &) = Load : &:r0_17, m0_8
# 190| r0_19(unsigned int) = Load : &:r0_18, ~m0_1
# 190| r0_20(glval<unsigned int &>) = VariableAddress[d] :
# 190| r0_21(unsigned int &) = Load : &:r0_20, m0_10
# 190| r0_22(unsigned int) = Load : &:r0_21, ~m0_1
# 186| m0_23(unknown) = InlineAsm : ~mu0_2, 0:r0_13, 1:r0_16, 2:r0_19, 3:r0_22
# 186| m0_24(unknown) = Chi : total:m0_1, partial:m0_23
# 192| v0_25(void) = NoOp :
# 184| v0_26(void) = ReturnVoid :
# 184| v0_27(void) = UnmodeledUse : mu*
# 184| v0_28(void) = AliasedUse : ~m0_24
# 184| v0_29(void) = ExitFunction :
# 198| int PureFunctions(char*, char*, int)
# 198| Block 0
@@ -852,20 +858,122 @@ ssa.cpp:
# 208| m0_8(unknown) = Chi : total:m0_5, partial:m0_7
# 209| r0_9(glval<unknown>) = FunctionAddress[memcpy] :
# 209| r0_10(glval<int>) = VariableAddress[y] :
# 209| r0_11(void *) = Convert : r0_10
# 209| r0_12(glval<int>) = VariableAddress[x] :
# 209| r0_13(void *) = Convert : r0_12
# 209| r0_14(int) = Constant[4] :
# 209| r0_15(void *) = Call : func:r0_9, 0:r0_11, 1:r0_13, 2:r0_14
# 209| v0_16(void) = ^SizedBufferReadSideEffect[1] : &:r0_13, r0_14, ~mu0_2
# 209| m0_17(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r0_11, r0_14
# 209| m0_18(unknown) = Chi : total:m0_8, partial:m0_17
# 210| r0_19(glval<int>) = VariableAddress[#return] :
# 210| r0_20(glval<int>) = VariableAddress[y] :
# 210| r0_21(int) = Load : &:r0_20, ~m0_18
# 210| m0_22(int) = Store : &:r0_19, r0_21
# 207| r0_23(glval<int>) = VariableAddress[#return] :
# 207| v0_24(void) = ReturnValue : &:r0_23, m0_22
# 207| v0_25(void) = UnmodeledUse : mu*
# 207| v0_26(void) = AliasedUse : ~m0_1
# 207| v0_27(void) = ExitFunction :
# 209| r0_11(int *) = CopyValue : r0_10
# 209| r0_12(void *) = Convert : r0_11
# 209| r0_13(glval<int>) = VariableAddress[x] :
# 209| r0_14(int *) = CopyValue : r0_13
# 209| r0_15(void *) = Convert : r0_14
# 209| r0_16(int) = Constant[4] :
# 209| r0_17(void *) = Call : func:r0_9, 0:r0_12, 1:r0_15, 2:r0_16
# 209| v0_18(void) = ^SizedBufferReadSideEffect[1] : &:r0_15, r0_16, ~mu0_2
# 209| m0_19(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r0_12, r0_16
# 209| m0_20(unknown) = Chi : total:m0_8, partial:m0_19
# 210| r0_21(glval<int>) = VariableAddress[#return] :
# 210| r0_22(glval<int>) = VariableAddress[y] :
# 210| r0_23(int) = Load : &:r0_22, ~m0_20
# 210| m0_24(int) = Store : &:r0_21, r0_23
# 207| r0_25(glval<int>) = VariableAddress[#return] :
# 207| v0_26(void) = ReturnValue : &:r0_25, m0_24
# 207| v0_27(void) = UnmodeledUse : mu*
# 207| v0_28(void) = AliasedUse : ~m0_1
# 207| v0_29(void) = ExitFunction :
# 213| void InitArray()
# 213| Block 0
# 213| v0_0(void) = EnterFunction :
# 213| m0_1(unknown) = AliasedDefinition :
# 213| mu0_2(unknown) = UnmodeledDefinition :
# 214| r0_3(glval<char[32]>) = VariableAddress[a_pad] :
# 214| m0_4(char[32]) = Uninitialized[a_pad] : &:r0_3
# 214| r0_5(glval<char[1]>) = StringConstant[""] :
# 214| r0_6(char[1]) = Load : &:r0_5, ~m0_1
# 214| m0_7(char[1]) = Store : &:r0_3, r0_6
# 214| m0_8(char[32]) = Chi : total:m0_4, partial:m0_7
# 214| r0_9(unknown[31]) = Constant[0] :
# 214| r0_10(int) = Constant[1] :
# 214| r0_11(glval<char>) = PointerAdd[1] : r0_3, r0_10
# 214| m0_12(unknown[31]) = Store : &:r0_11, r0_9
# 214| m0_13(char[32]) = Chi : total:m0_8, partial:m0_12
# 215| r0_14(glval<char[4]>) = VariableAddress[a_nopad] :
# 215| r0_15(glval<char[4]>) = StringConstant["foo"] :
# 215| r0_16(char[4]) = Load : &:r0_15, ~m0_1
# 215| m0_17(char[4]) = Store : &:r0_14, r0_16
# 216| r0_18(glval<char[5]>) = VariableAddress[a_infer] :
# 216| r0_19(glval<char[5]>) = StringConstant["blah"] :
# 216| r0_20(char[5]) = Load : &:r0_19, ~m0_1
# 216| m0_21(char[5]) = Store : &:r0_18, r0_20
# 217| r0_22(glval<char[2]>) = VariableAddress[b] :
# 217| m0_23(char[2]) = Uninitialized[b] : &:r0_22
# 218| r0_24(glval<char[2]>) = VariableAddress[c] :
# 218| m0_25(char[2]) = Uninitialized[c] : &:r0_24
# 218| r0_26(int) = Constant[0] :
# 218| r0_27(glval<char>) = PointerAdd[1] : r0_24, r0_26
# 218| r0_28(unknown[2]) = Constant[0] :
# 218| m0_29(unknown[2]) = Store : &:r0_27, r0_28
# 219| r0_30(glval<char[2]>) = VariableAddress[d] :
# 219| m0_31(char[2]) = Uninitialized[d] : &:r0_30
# 219| r0_32(int) = Constant[0] :
# 219| r0_33(glval<char>) = PointerAdd[1] : r0_30, r0_32
# 219| r0_34(char) = Constant[0] :
# 219| m0_35(char) = Store : &:r0_33, r0_34
# 219| m0_36(char[2]) = Chi : total:m0_31, partial:m0_35
# 219| r0_37(int) = Constant[1] :
# 219| r0_38(glval<char>) = PointerAdd[1] : r0_30, r0_37
# 219| r0_39(char) = Constant[0] :
# 219| m0_40(char) = Store : &:r0_38, r0_39
# 219| m0_41(char[2]) = Chi : total:m0_36, partial:m0_40
# 220| r0_42(glval<char[2]>) = VariableAddress[e] :
# 220| m0_43(char[2]) = Uninitialized[e] : &:r0_42
# 220| r0_44(int) = Constant[0] :
# 220| r0_45(glval<char>) = PointerAdd[1] : r0_42, r0_44
# 220| r0_46(char) = Constant[0] :
# 220| m0_47(char) = Store : &:r0_45, r0_46
# 220| m0_48(char[2]) = Chi : total:m0_43, partial:m0_47
# 220| r0_49(int) = Constant[1] :
# 220| r0_50(glval<char>) = PointerAdd[1] : r0_42, r0_49
# 220| r0_51(char) = Constant[1] :
# 220| m0_52(char) = Store : &:r0_50, r0_51
# 220| m0_53(char[2]) = Chi : total:m0_48, partial:m0_52
# 221| r0_54(glval<char[3]>) = VariableAddress[f] :
# 221| m0_55(char[3]) = Uninitialized[f] : &:r0_54
# 221| r0_56(int) = Constant[0] :
# 221| r0_57(glval<char>) = PointerAdd[1] : r0_54, r0_56
# 221| r0_58(char) = Constant[0] :
# 221| m0_59(char) = Store : &:r0_57, r0_58
# 221| m0_60(char[3]) = Chi : total:m0_55, partial:m0_59
# 221| r0_61(int) = Constant[1] :
# 221| r0_62(glval<char>) = PointerAdd[1] : r0_54, r0_61
# 221| r0_63(unknown[2]) = Constant[0] :
# 221| m0_64(unknown[2]) = Store : &:r0_62, r0_63
# 221| m0_65(char[3]) = Chi : total:m0_60, partial:m0_64
# 222| v0_66(void) = NoOp :
# 213| v0_67(void) = ReturnVoid :
# 213| v0_68(void) = UnmodeledUse : mu*
# 213| v0_69(void) = AliasedUse : ~m0_1
# 213| v0_70(void) = ExitFunction :
# 226| char StringLiteralAliasing()
# 226| Block 0
# 226| v0_0(void) = EnterFunction :
# 226| m0_1(unknown) = AliasedDefinition :
# 226| mu0_2(unknown) = UnmodeledDefinition :
# 227| r0_3(glval<unknown>) = FunctionAddress[ExternalFunc] :
# 227| v0_4(void) = Call : func:r0_3
# 227| m0_5(unknown) = ^CallSideEffect : ~m0_1
# 227| m0_6(unknown) = Chi : total:m0_1, partial:m0_5
# 229| r0_7(glval<char *>) = VariableAddress[s] :
# 229| r0_8(glval<char[8]>) = StringConstant["Literal"] :
# 229| r0_9(char *) = Convert : r0_8
# 229| m0_10(char *) = Store : &:r0_7, r0_9
# 230| r0_11(glval<char>) = VariableAddress[#return] :
# 230| r0_12(glval<char *>) = VariableAddress[s] :
# 230| r0_13(char *) = Load : &:r0_12, m0_10
# 230| r0_14(int) = Constant[2] :
# 230| r0_15(glval<char>) = PointerAdd[1] : r0_13, r0_14
# 230| r0_16(char) = Load : &:r0_15, ~m0_1
# 230| m0_17(char) = Store : &:r0_11, r0_16
# 226| r0_18(glval<char>) = VariableAddress[#return] :
# 226| v0_19(void) = ReturnValue : &:r0_18, m0_17
# 226| v0_20(void) = UnmodeledUse : mu*
# 226| v0_21(void) = AliasedUse : ~m0_6
# 226| v0_22(void) = ExitFunction :

View File

@@ -210,3 +210,22 @@ int ModeledCallTarget(int x) {
return y;
}
void InitArray() {
char a_pad[32] = "";
char a_nopad[4] = "foo";
char a_infer[] = "blah";
char b[2];
char c[2] = {};
char d[2] = { 0 };
char e[2] = { 0, 1 };
char f[3] = { 0 };
}
extern void ExternalFunc();
char StringLiteralAliasing() {
ExternalFunc();
const char* s = "Literal";
return s[2]; // Should be defined by `AliasedDefinition`, not `Chi` or `CallSideEffect`.
}

View File

@@ -218,7 +218,8 @@ ssa.cpp:
# 70| r1_3(int) = Constant[1] :
# 70| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
# 70| m1_5(char *) = Store : &:r1_1, r1_4
# 70| mu1_6(char) = Store : &:r1_2, r1_0
# 70| r1_6(glval<char>) = CopyValue : r1_2
# 70| mu1_7(char) = Store : &:r1_6, r1_0
#-----| Goto (back edge) -> Block 3
# 71| Block 2
@@ -330,16 +331,17 @@ ssa.cpp:
# 96| m0_8(Point) = Store : &:r0_5, r0_7
# 97| r0_9(glval<unknown>) = FunctionAddress[Escape] :
# 97| r0_10(glval<Point>) = VariableAddress[a] :
# 97| r0_11(void *) = Convert : r0_10
# 97| v0_12(void) = Call : func:r0_9, 0:r0_11
# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2
# 97| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_11, ~mu0_2
# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11
# 98| v0_16(void) = NoOp :
# 95| v0_17(void) = ReturnVoid :
# 95| v0_18(void) = UnmodeledUse : mu*
# 95| v0_19(void) = AliasedUse : ~mu0_2
# 95| v0_20(void) = ExitFunction :
# 97| r0_11(Point *) = CopyValue : r0_10
# 97| r0_12(void *) = Convert : r0_11
# 97| v0_13(void) = Call : func:r0_9, 0:r0_12
# 97| mu0_14(unknown) = ^CallSideEffect : ~mu0_2
# 97| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_12, ~mu0_2
# 97| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12
# 98| v0_17(void) = NoOp :
# 95| v0_18(void) = ReturnVoid :
# 95| v0_19(void) = UnmodeledUse : mu*
# 95| v0_20(void) = AliasedUse : ~mu0_2
# 95| v0_21(void) = ExitFunction :
# 100| void MustTotallyOverlap(Point)
# 100| Block 0
@@ -383,16 +385,17 @@ ssa.cpp:
# 107| m0_14(int) = Store : &:r0_10, r0_13
# 108| r0_15(glval<unknown>) = FunctionAddress[Escape] :
# 108| r0_16(glval<Point>) = VariableAddress[a] :
# 108| r0_17(void *) = Convert : r0_16
# 108| v0_18(void) = Call : func:r0_15, 0:r0_17
# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2
# 108| v0_20(void) = ^BufferReadSideEffect[0] : &:r0_17, ~mu0_2
# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_17
# 109| v0_22(void) = NoOp :
# 105| v0_23(void) = ReturnVoid :
# 105| v0_24(void) = UnmodeledUse : mu*
# 105| v0_25(void) = AliasedUse : ~mu0_2
# 105| v0_26(void) = ExitFunction :
# 108| r0_17(Point *) = CopyValue : r0_16
# 108| r0_18(void *) = Convert : r0_17
# 108| v0_19(void) = Call : func:r0_15, 0:r0_18
# 108| mu0_20(unknown) = ^CallSideEffect : ~mu0_2
# 108| v0_21(void) = ^BufferReadSideEffect[0] : &:r0_18, ~mu0_2
# 108| mu0_22(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_18
# 109| v0_23(void) = NoOp :
# 105| v0_24(void) = ReturnVoid :
# 105| v0_25(void) = UnmodeledUse : mu*
# 105| v0_26(void) = AliasedUse : ~mu0_2
# 105| v0_27(void) = ExitFunction :
# 111| void MayPartiallyOverlap(int, int)
# 111| Block 0
@@ -448,16 +451,17 @@ ssa.cpp:
# 118| m0_20(Point) = Store : &:r0_17, r0_19
# 119| r0_21(glval<unknown>) = FunctionAddress[Escape] :
# 119| r0_22(glval<Point>) = VariableAddress[a] :
# 119| r0_23(void *) = Convert : r0_22
# 119| v0_24(void) = Call : func:r0_21, 0:r0_23
# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2
# 119| v0_26(void) = ^BufferReadSideEffect[0] : &:r0_23, ~mu0_2
# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23
# 120| v0_28(void) = NoOp :
# 116| v0_29(void) = ReturnVoid :
# 116| v0_30(void) = UnmodeledUse : mu*
# 116| v0_31(void) = AliasedUse : ~mu0_2
# 116| v0_32(void) = ExitFunction :
# 119| r0_23(Point *) = CopyValue : r0_22
# 119| r0_24(void *) = Convert : r0_23
# 119| v0_25(void) = Call : func:r0_21, 0:r0_24
# 119| mu0_26(unknown) = ^CallSideEffect : ~mu0_2
# 119| v0_27(void) = ^BufferReadSideEffect[0] : &:r0_24, ~mu0_2
# 119| mu0_28(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_24
# 120| v0_29(void) = NoOp :
# 116| v0_30(void) = ReturnVoid :
# 116| v0_31(void) = UnmodeledUse : mu*
# 116| v0_32(void) = AliasedUse : ~mu0_2
# 116| v0_33(void) = ExitFunction :
# 122| void MergeMustExactlyOverlap(bool, int, int)
# 122| Block 0
@@ -741,20 +745,22 @@ ssa.cpp:
# 184| m0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
# 189| r0_11(glval<unsigned int &>) = VariableAddress[a] :
# 189| r0_12(unsigned int &) = Load : &:r0_11, m0_4
# 189| r0_13(glval<unsigned int &>) = VariableAddress[b] :
# 189| r0_14(unsigned int &) = Load : &:r0_13, m0_6
# 190| r0_15(glval<unsigned int &>) = VariableAddress[c] :
# 190| r0_16(unsigned int &) = Load : &:r0_15, m0_8
# 190| r0_17(unsigned int) = Load : &:r0_16, ~mu0_2
# 190| r0_18(glval<unsigned int &>) = VariableAddress[d] :
# 190| r0_19(unsigned int &) = Load : &:r0_18, m0_10
# 190| r0_20(unsigned int) = Load : &:r0_19, ~mu0_2
# 186| mu0_21(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_14, 2:r0_17, 3:r0_20
# 192| v0_22(void) = NoOp :
# 184| v0_23(void) = ReturnVoid :
# 184| v0_24(void) = UnmodeledUse : mu*
# 184| v0_25(void) = AliasedUse : ~mu0_2
# 184| v0_26(void) = ExitFunction :
# 189| r0_13(glval<unsigned int>) = CopyValue : r0_12
# 189| r0_14(glval<unsigned int &>) = VariableAddress[b] :
# 189| r0_15(unsigned int &) = Load : &:r0_14, m0_6
# 189| r0_16(glval<unsigned int>) = CopyValue : r0_15
# 190| r0_17(glval<unsigned int &>) = VariableAddress[c] :
# 190| r0_18(unsigned int &) = Load : &:r0_17, m0_8
# 190| r0_19(unsigned int) = Load : &:r0_18, ~mu0_2
# 190| r0_20(glval<unsigned int &>) = VariableAddress[d] :
# 190| r0_21(unsigned int &) = Load : &:r0_20, m0_10
# 190| r0_22(unsigned int) = Load : &:r0_21, ~mu0_2
# 186| mu0_23(unknown) = InlineAsm : ~mu0_2, 0:r0_13, 1:r0_16, 2:r0_19, 3:r0_22
# 192| v0_24(void) = NoOp :
# 184| v0_25(void) = ReturnVoid :
# 184| v0_26(void) = UnmodeledUse : mu*
# 184| v0_27(void) = AliasedUse : ~mu0_2
# 184| v0_28(void) = ExitFunction :
# 198| int PureFunctions(char*, char*, int)
# 198| Block 0
@@ -817,19 +823,112 @@ ssa.cpp:
# 208| mu0_6(int) = Uninitialized[y] : &:r0_5
# 209| r0_7(glval<unknown>) = FunctionAddress[memcpy] :
# 209| r0_8(glval<int>) = VariableAddress[y] :
# 209| r0_9(void *) = Convert : r0_8
# 209| r0_10(glval<int>) = VariableAddress[x] :
# 209| r0_11(void *) = Convert : r0_10
# 209| r0_12(int) = Constant[4] :
# 209| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12
# 209| v0_14(void) = ^SizedBufferReadSideEffect[1] : &:r0_11, r0_12, ~mu0_2
# 209| mu0_15(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r0_9, r0_12
# 210| r0_16(glval<int>) = VariableAddress[#return] :
# 210| r0_17(glval<int>) = VariableAddress[y] :
# 210| r0_18(int) = Load : &:r0_17, ~mu0_2
# 210| m0_19(int) = Store : &:r0_16, r0_18
# 207| r0_20(glval<int>) = VariableAddress[#return] :
# 207| v0_21(void) = ReturnValue : &:r0_20, m0_19
# 207| v0_22(void) = UnmodeledUse : mu*
# 207| v0_23(void) = AliasedUse : ~mu0_2
# 207| v0_24(void) = ExitFunction :
# 209| r0_9(int *) = CopyValue : r0_8
# 209| r0_10(void *) = Convert : r0_9
# 209| r0_11(glval<int>) = VariableAddress[x] :
# 209| r0_12(int *) = CopyValue : r0_11
# 209| r0_13(void *) = Convert : r0_12
# 209| r0_14(int) = Constant[4] :
# 209| r0_15(void *) = Call : func:r0_7, 0:r0_10, 1:r0_13, 2:r0_14
# 209| v0_16(void) = ^SizedBufferReadSideEffect[1] : &:r0_13, r0_14, ~mu0_2
# 209| mu0_17(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r0_10, r0_14
# 210| r0_18(glval<int>) = VariableAddress[#return] :
# 210| r0_19(glval<int>) = VariableAddress[y] :
# 210| r0_20(int) = Load : &:r0_19, ~mu0_2
# 210| m0_21(int) = Store : &:r0_18, r0_20
# 207| r0_22(glval<int>) = VariableAddress[#return] :
# 207| v0_23(void) = ReturnValue : &:r0_22, m0_21
# 207| v0_24(void) = UnmodeledUse : mu*
# 207| v0_25(void) = AliasedUse : ~mu0_2
# 207| v0_26(void) = ExitFunction :
# 213| void InitArray()
# 213| Block 0
# 213| v0_0(void) = EnterFunction :
# 213| mu0_1(unknown) = AliasedDefinition :
# 213| mu0_2(unknown) = UnmodeledDefinition :
# 214| r0_3(glval<char[32]>) = VariableAddress[a_pad] :
# 214| mu0_4(char[32]) = Uninitialized[a_pad] : &:r0_3
# 214| r0_5(glval<char[1]>) = StringConstant[""] :
# 214| r0_6(char[1]) = Load : &:r0_5, ~mu0_2
# 214| mu0_7(char[1]) = Store : &:r0_3, r0_6
# 214| r0_8(unknown[31]) = Constant[0] :
# 214| r0_9(int) = Constant[1] :
# 214| r0_10(glval<char>) = PointerAdd[1] : r0_3, r0_9
# 214| mu0_11(unknown[31]) = Store : &:r0_10, r0_8
# 215| r0_12(glval<char[4]>) = VariableAddress[a_nopad] :
# 215| r0_13(glval<char[4]>) = StringConstant["foo"] :
# 215| r0_14(char[4]) = Load : &:r0_13, ~mu0_2
# 215| m0_15(char[4]) = Store : &:r0_12, r0_14
# 216| r0_16(glval<char[5]>) = VariableAddress[a_infer] :
# 216| r0_17(glval<char[5]>) = StringConstant["blah"] :
# 216| r0_18(char[5]) = Load : &:r0_17, ~mu0_2
# 216| m0_19(char[5]) = Store : &:r0_16, r0_18
# 217| r0_20(glval<char[2]>) = VariableAddress[b] :
# 217| m0_21(char[2]) = Uninitialized[b] : &:r0_20
# 218| r0_22(glval<char[2]>) = VariableAddress[c] :
# 218| mu0_23(char[2]) = Uninitialized[c] : &:r0_22
# 218| r0_24(int) = Constant[0] :
# 218| r0_25(glval<char>) = PointerAdd[1] : r0_22, r0_24
# 218| r0_26(unknown[2]) = Constant[0] :
# 218| mu0_27(unknown[2]) = Store : &:r0_25, r0_26
# 219| r0_28(glval<char[2]>) = VariableAddress[d] :
# 219| mu0_29(char[2]) = Uninitialized[d] : &:r0_28
# 219| r0_30(int) = Constant[0] :
# 219| r0_31(glval<char>) = PointerAdd[1] : r0_28, r0_30
# 219| r0_32(char) = Constant[0] :
# 219| mu0_33(char) = Store : &:r0_31, r0_32
# 219| r0_34(int) = Constant[1] :
# 219| r0_35(glval<char>) = PointerAdd[1] : r0_28, r0_34
# 219| r0_36(char) = Constant[0] :
# 219| mu0_37(char) = Store : &:r0_35, r0_36
# 220| r0_38(glval<char[2]>) = VariableAddress[e] :
# 220| mu0_39(char[2]) = Uninitialized[e] : &:r0_38
# 220| r0_40(int) = Constant[0] :
# 220| r0_41(glval<char>) = PointerAdd[1] : r0_38, r0_40
# 220| r0_42(char) = Constant[0] :
# 220| mu0_43(char) = Store : &:r0_41, r0_42
# 220| r0_44(int) = Constant[1] :
# 220| r0_45(glval<char>) = PointerAdd[1] : r0_38, r0_44
# 220| r0_46(char) = Constant[1] :
# 220| mu0_47(char) = Store : &:r0_45, r0_46
# 221| r0_48(glval<char[3]>) = VariableAddress[f] :
# 221| mu0_49(char[3]) = Uninitialized[f] : &:r0_48
# 221| r0_50(int) = Constant[0] :
# 221| r0_51(glval<char>) = PointerAdd[1] : r0_48, r0_50
# 221| r0_52(char) = Constant[0] :
# 221| mu0_53(char) = Store : &:r0_51, r0_52
# 221| r0_54(int) = Constant[1] :
# 221| r0_55(glval<char>) = PointerAdd[1] : r0_48, r0_54
# 221| r0_56(unknown[2]) = Constant[0] :
# 221| mu0_57(unknown[2]) = Store : &:r0_55, r0_56
# 222| v0_58(void) = NoOp :
# 213| v0_59(void) = ReturnVoid :
# 213| v0_60(void) = UnmodeledUse : mu*
# 213| v0_61(void) = AliasedUse : ~mu0_2
# 213| v0_62(void) = ExitFunction :
# 226| char StringLiteralAliasing()
# 226| Block 0
# 226| v0_0(void) = EnterFunction :
# 226| mu0_1(unknown) = AliasedDefinition :
# 226| mu0_2(unknown) = UnmodeledDefinition :
# 227| r0_3(glval<unknown>) = FunctionAddress[ExternalFunc] :
# 227| v0_4(void) = Call : func:r0_3
# 227| mu0_5(unknown) = ^CallSideEffect : ~mu0_2
# 229| r0_6(glval<char *>) = VariableAddress[s] :
# 229| r0_7(glval<char[8]>) = StringConstant["Literal"] :
# 229| r0_8(char *) = Convert : r0_7
# 229| m0_9(char *) = Store : &:r0_6, r0_8
# 230| r0_10(glval<char>) = VariableAddress[#return] :
# 230| r0_11(glval<char *>) = VariableAddress[s] :
# 230| r0_12(char *) = Load : &:r0_11, m0_9
# 230| r0_13(int) = Constant[2] :
# 230| r0_14(glval<char>) = PointerAdd[1] : r0_12, r0_13
# 230| r0_15(char) = Load : &:r0_14, ~mu0_2
# 230| m0_16(char) = Store : &:r0_10, r0_15
# 226| r0_17(glval<char>) = VariableAddress[#return] :
# 226| v0_18(void) = ReturnValue : &:r0_17, m0_16
# 226| v0_19(void) = UnmodeledUse : mu*
# 226| v0_20(void) = AliasedUse : ~mu0_2
# 226| v0_21(void) = ExitFunction :

View File

@@ -13,7 +13,7 @@
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(const c<int> &) -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(c<int> &&) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(const c<int> &) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:14:26:14:26 | c | c<T>::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<T> | Unknown literal |
| copy_from_prototype.cpp:14:26:14:26 | c | c<T>::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<T> | X |
| copy_from_prototype.cpp:14:26:14:26 | c | c<int>::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d() -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(const d &) -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |

View File

@@ -1,3 +1,7 @@
| file://:0:0:0:0 | __i | file://:0:0:0:0 | unsigned long |
| file://:0:0:0:0 | uls | file://:0:0:0:0 | unsigned long |
| file://:0:0:0:0 | uls | file://:0:0:0:0 | unsigned long |
| file://:0:0:0:0 | uls | file://:0:0:0:0 | unsigned long |
| segfault.cpp:25:46:25:65 | call to S | file://:0:0:0:0 | void |
| segfault.cpp:25:46:25:65 | call to S | file://:0:0:0:0 | void |
| segfault.cpp:25:48:25:55 | __second | segfault.cpp:15:7:15:11 | tuple |

View File

@@ -649,12 +649,14 @@
| test.c:397:9:397:11 | Constant: ++ ... | positive strictlyPositive |
| test.c:397:9:397:11 | Load: ++ ... | positive |
| test.c:397:9:397:11 | Store: ++ ... | positive strictlyPositive |
| test.c:397:9:397:14 | CopyValue: ... , ... | positive strictlyPositive |
| test.c:397:14:397:14 | Load: y | positive strictlyPositive |
| test.c:398:3:398:23 | Store: ... = ... | positive strictlyPositive |
| test.c:398:9:398:11 | Add: ... ++ | positive strictlyPositive |
| test.c:398:9:398:11 | Constant: ... ++ | positive strictlyPositive |
| test.c:398:9:398:11 | Load: ... ++ | positive strictlyPositive |
| test.c:398:9:398:11 | Store: ... ++ | positive strictlyPositive |
| test.c:398:9:398:22 | CopyValue: ... , ... | positive strictlyPositive |
| test.c:398:14:398:19 | Add: ... += ... | positive strictlyPositive |
| test.c:398:14:398:19 | Load: ... += ... | positive strictlyPositive |
| test.c:398:14:398:19 | Store: ... += ... | positive strictlyPositive |

View File

@@ -1,53 +0,0 @@
| staticlocals__staticlocals_f2_extractor | false | 22465 | 22465 | f2 |
| staticlocals__staticlocals_f2_extractor | false | 22470 | 22470 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22472 | 22472 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22474 | 22474 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22476 | 22476 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22478 | 22478 | return ... |
| staticlocals__staticlocals_f2_extractor | false | 22480 | 22480 | { ... } |
| staticlocals__staticlocals_f2_extractor | false | 22482 | 22482 | call to C |
| staticlocals__staticlocals_f2_extractor | false | 22484 | 22484 | initializer for c |
| staticlocals__staticlocals_f2_extractor | false | 22486 | 22486 | call to addOne |
| staticlocals__staticlocals_f2_extractor | false | 22490 | 22490 | 2 |
| staticlocals__staticlocals_f2_extractor | false | 22493 | 22493 | initializer for j |
| staticlocals__staticlocals_f2_extractor | false | 22494 | 22494 | call to addOne |
| staticlocals__staticlocals_f2_extractor | false | 22499 | 22499 | 2 |
| staticlocals__staticlocals_f2_extractor | false | 22500 | 22500 | initializer for two |
| staticlocals__staticlocals_f2_extractor | false | 22503 | 22503 | two |
| staticlocals__staticlocals_f2_extractor | false | 22508 | 22508 | initializer for i |
| staticlocals__staticlocals_f2_extractor | true | 22470 | 22500 | |
| staticlocals__staticlocals_f2_extractor | true | 22472 | 22474 | |
| staticlocals__staticlocals_f2_extractor | true | 22474 | 22476 | |
| staticlocals__staticlocals_f2_extractor | true | 22476 | 22478 | |
| staticlocals__staticlocals_f2_extractor | true | 22478 | 22465 | |
| staticlocals__staticlocals_f2_extractor | true | 22480 | 22470 | |
| staticlocals__staticlocals_f2_extractor | true | 22499 | 22472 | |
| staticlocals__staticlocals_f2_extractor | true | 22500 | 22499 | |
| staticlocals__staticlocals_f2_ql | false | 22465 | 22465 | f2 |
| staticlocals__staticlocals_f2_ql | false | 22470 | 22470 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22472 | 22472 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22474 | 22474 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22476 | 22476 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22478 | 22478 | return ... |
| staticlocals__staticlocals_f2_ql | false | 22480 | 22480 | { ... } |
| staticlocals__staticlocals_f2_ql | false | 22482 | 22482 | call to C |
| staticlocals__staticlocals_f2_ql | false | 22484 | 22484 | initializer for c |
| staticlocals__staticlocals_f2_ql | false | 22486 | 22486 | call to addOne |
| staticlocals__staticlocals_f2_ql | false | 22490 | 22490 | 2 |
| staticlocals__staticlocals_f2_ql | false | 22493 | 22493 | initializer for j |
| staticlocals__staticlocals_f2_ql | false | 22494 | 22494 | call to addOne |
| staticlocals__staticlocals_f2_ql | false | 22499 | 22499 | 2 |
| staticlocals__staticlocals_f2_ql | false | 22500 | 22500 | initializer for two |
| staticlocals__staticlocals_f2_ql | false | 22503 | 22503 | two |
| staticlocals__staticlocals_f2_ql | false | 22508 | 22508 | initializer for i |
| staticlocals__staticlocals_f2_ql | true | 22470 | 22500 | |
| staticlocals__staticlocals_f2_ql | true | 22472 | 22474 | |
| staticlocals__staticlocals_f2_ql | true | 22474 | 22476 | |
| staticlocals__staticlocals_f2_ql | true | 22476 | 22478 | |
| staticlocals__staticlocals_f2_ql | true | 22476 | 22484 | |
| staticlocals__staticlocals_f2_ql | true | 22478 | 22465 | |
| staticlocals__staticlocals_f2_ql | true | 22480 | 22470 | |
| staticlocals__staticlocals_f2_ql | true | 22482 | 22478 | |
| staticlocals__staticlocals_f2_ql | true | 22484 | 22482 | |
| staticlocals__staticlocals_f2_ql | true | 22499 | 22472 | |
| staticlocals__staticlocals_f2_ql | true | 22500 | 22499 | |

View File

@@ -1,10 +0,0 @@
// query-type: graph
import Compare
from
Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y,
string label
where
AllCFG::qltestGraph(scopeElement, scopeString, isEdge, x, y, label) and
differentScope(scopeElement)
select scopeString, isEdge, x, y, label

View File

@@ -1,8 +1,8 @@
missingOperand
| condition_decls.cpp:16:6:16:20 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) |
| condition_decls.cpp:26:3:36:3 | Switch: switch (...) ... | Instruction 'Switch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) |
| condition_decls.cpp:41:9:41:23 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) |
| condition_decls.cpp:48:39:48:53 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) |
| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) |
| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) |
| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) |
| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) |
| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() |
| misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |

View File

@@ -1,3 +0,0 @@
| staticlocals__staticlocals_f2 | file://:0:0:0:0 | call to C | staticlocals.cpp:30:1:30:1 | return ... | Standard edge, only from QL | |
| staticlocals__staticlocals_f2 | file://:0:0:0:0 | initializer for c | file://:0:0:0:0 | call to C | Standard edge, only from QL | |
| staticlocals__staticlocals_f2 | staticlocals.cpp:29:5:29:17 | declaration | file://:0:0:0:0 | initializer for c | Standard edge, only from QL | |

View File

@@ -1,13 +0,0 @@
import Compare
string describeTemplate(ControlFlowNode node) {
node.isFromTemplateInstantiation(_) and
result = "instantiation"
or
node.isFromUninstantiatedTemplate(_) and
result = "uninstantiated"
}
from ControlFlowNode n1, ControlFlowNode n2, string msg
where differentEdge(n1, n2, msg)
select getScopeName(n1), n1, n2, msg, concat(describeTemplate(n1), ", ")

View File

@@ -0,0 +1,19 @@
class A {
public:
void foo();
int k;
};
class B {
public:
template <typename T>
B(T x) {
int k = x.k;
x.foo();
}
};
A a;
B b(a);

View File

@@ -0,0 +1,2 @@
| test.cpp:13:15:13:15 | k |
| test.cpp:14:7:14:9 | foo |

View File

@@ -0,0 +1,4 @@
import cpp
from Literal l
select l

View File

@@ -1,6 +1,6 @@
| file://:0:0:0:0 | __va_list_tag | <none> |
| test.cpp:3:8:3:9 | s1<<expression>> | <none> |
| test.cpp:3:8:3:9 | s1<<unnamed>> | <none> |
| test.cpp:3:8:3:9 | s1<<expression>> | {...} |
| test.cpp:3:8:3:9 | s1<<unnamed>> | (null) |
| test.cpp:5:8:5:9 | s2<T> | T |
| test.cpp:5:8:5:9 | s2<T> | T |
| test.cpp:7:8:7:9 | s3<T, <unnamed>> | (unnamed) |

View File

@@ -1,6 +1,12 @@
| file://:0:0:0:0 | |
| file://:0:0:0:0 | 0 |
| file://:0:0:0:0 | (global namespace) |
| file://:0:0:0:0 | B |
| file://:0:0:0:0 | X |
| file://:0:0:0:0 | X |
| file://:0:0:0:0 | X |
| file://:0:0:0:0 | X |
| file://:0:0:0:0 | Y |
| file://:0:0:0:0 | __va_list_tag |
| file://:0:0:0:0 | __va_list_tag & |
| file://:0:0:0:0 | __va_list_tag && |

View File

@@ -317,8 +317,8 @@
| test.cpp:19:9:19:24 | call to expression |
| test.cpp:19:9:19:25 | ExprStmt |
| test.cpp:19:9:19:25 | ExprStmt |
| test.cpp:19:15:19:18 | Unknown literal |
| test.cpp:19:15:19:18 | call to funx |
| test.cpp:19:15:19:18 | funx |
| test.cpp:19:20:19:23 | (reference to) |
| test.cpp:19:20:19:23 | valx |
| test.cpp:19:20:19:23 | valx |
@@ -356,8 +356,8 @@
| test.cpp:30:13:30:22 | call to expression |
| test.cpp:30:13:30:23 | ExprStmt |
| test.cpp:30:13:30:23 | ExprStmt |
| test.cpp:30:15:30:20 | Unknown literal |
| test.cpp:30:15:30:20 | call to eparse |
| test.cpp:30:15:30:20 | eparse |
| test.cpp:31:9:31:9 | return ... |
| test.cpp:31:9:31:9 | return ... |
| test.cpp:34:6:34:11 | define |

View File

@@ -0,0 +1,4 @@
template <int i>
class Int { };
Int<10> i;

View File

@@ -0,0 +1,2 @@
| test.cpp:2:7:2:9 | Int<10> | file://:0:0:0:0 | int | test.cpp:4:5:4:6 | 10 |
| test.cpp:2:7:2:9 | Int<i> | file://:0:0:0:0 | int | file://:0:0:0:0 | i |

View File

@@ -0,0 +1,4 @@
import cpp
from Class c
select c, c.getATemplateArgumentKind(), c.getATemplateArgument()

View File

@@ -0,0 +1,5 @@
// semmle-extractor-options: --edg --trap_container=folder --edg --trap-compression=none
template <int i>
int addToSelf() { return i + i; };
int bar() { return addToSelf<10>(); }

View File

@@ -0,0 +1,2 @@
| test.cpp:3:5:3:5 | addToSelf | file://:0:0:0:0 | int | test.cpp:5:30:5:31 | 10 |
| test.cpp:3:5:3:13 | addToSelf | file://:0:0:0:0 | int | file://:0:0:0:0 | i |

View File

@@ -0,0 +1,4 @@
import cpp
from Function f
select f, f.getATemplateArgumentKind(), f.getATemplateArgument()

View File

@@ -0,0 +1,19 @@
// semmle-extractor-options: --edg --trap_container=folder --edg --trap-compression=none
template<int x>
struct C { };
static const int one1 = 1, one2 = 1;
C<one1> c = C<one2>();
C<one1 + one2> e;
template<typename T, T X>
struct D { };
D<int, 2> a;
D<long, 2> b;
template<typename T, T* X>
struct E { };
E<int, nullptr> z;

View File

@@ -0,0 +1,13 @@
| test.cpp:3:8:3:8 | C<1> | 0 | int | test.cpp:5:25:5:25 | 1 |
| test.cpp:3:8:3:8 | C<2> | 0 | int | file://:0:0:0:0 | 2 |
| test.cpp:3:8:3:8 | C<x> | 0 | int | file://:0:0:0:0 | x |
| test.cpp:10:8:10:8 | D<T, X> | 0 | <none> | test.cpp:9:19:9:19 | T |
| test.cpp:10:8:10:8 | D<T, X> | 1 | T | file://:0:0:0:0 | X |
| test.cpp:10:8:10:8 | D<int, 2> | 0 | <none> | file://:0:0:0:0 | int |
| test.cpp:10:8:10:8 | D<int, 2> | 1 | int | test.cpp:12:8:12:8 | 2 |
| test.cpp:10:8:10:8 | D<long, 2L> | 0 | <none> | file://:0:0:0:0 | long |
| test.cpp:10:8:10:8 | D<long, 2L> | 1 | long | file://:0:0:0:0 | 2 |
| test.cpp:16:8:16:8 | E<T, X> | 0 | <none> | test.cpp:15:19:15:19 | T |
| test.cpp:16:8:16:8 | E<T, X> | 1 | T * | file://:0:0:0:0 | X |
| test.cpp:16:8:16:8 | E<int, (int *)nullptr> | 0 | <none> | file://:0:0:0:0 | int |
| test.cpp:16:8:16:8 | E<int, (int *)nullptr> | 1 | int * | file://:0:0:0:0 | 0 |

View File

@@ -0,0 +1,14 @@
import cpp
string maybeGetTemplateArgumentKind(Declaration d, int i) {
(
if exists(d.getTemplateArgumentKind(i))
then result = d.getTemplateArgumentKind(i).toString()
else result = "<none>"
) and
i = [0 .. d.getNumberOfTemplateArguments()]
}
from Declaration d, int i
where i >= 0 and i < d.getNumberOfTemplateArguments()
select d, i, maybeGetTemplateArgumentKind(d, i), d.getTemplateArgument(i)

View File

@@ -300,45 +300,47 @@ test.cpp:
# 44| valnum = r0_7
# 44| r0_27(int *) = Load : &:r0_26, m0_8
# 44| valnum = m0_8
# 44| m0_28(int) = Store : &:r0_27, r0_25
# 44| r0_28(glval<int>) = CopyValue : r0_27
# 44| valnum = m0_8
# 44| m0_29(int) = Store : &:r0_28, r0_25
# 44| valnum = r0_25
# 44| m0_29(unknown) = Chi : total:m0_1, partial:m0_28
# 44| m0_30(unknown) = Chi : total:m0_1, partial:m0_29
# 44| valnum = unique
# 45| r0_30(glval<int>) = VariableAddress[p0] :
# 45| r0_31(glval<int>) = VariableAddress[p0] :
# 45| valnum = r0_3
# 45| r0_31(int) = Load : &:r0_30, m0_4
# 45| r0_32(int) = Load : &:r0_31, m0_4
# 45| valnum = m0_4
# 45| r0_32(glval<int>) = VariableAddress[p1] :
# 45| r0_33(glval<int>) = VariableAddress[p1] :
# 45| valnum = r0_5
# 45| r0_33(int) = Load : &:r0_32, m0_6
# 45| r0_34(int) = Load : &:r0_33, m0_6
# 45| valnum = m0_6
# 45| r0_34(int) = Add : r0_31, r0_33
# 45| r0_35(int) = Add : r0_32, r0_34
# 45| valnum = r0_19
# 45| r0_35(glval<int>) = VariableAddress[global03] :
# 45| r0_36(glval<int>) = VariableAddress[global03] :
# 45| valnum = r0_20
# 45| r0_36(int) = Load : &:r0_35, ~m0_29
# 45| r0_37(int) = Load : &:r0_36, ~m0_30
# 45| valnum = unique
# 45| r0_37(int) = Add : r0_34, r0_36
# 45| valnum = r0_37
# 45| r0_38(glval<int>) = VariableAddress[x] :
# 45| r0_38(int) = Add : r0_35, r0_37
# 45| valnum = r0_38
# 45| r0_39(glval<int>) = VariableAddress[x] :
# 45| valnum = r0_9
# 45| m0_39(int) = Store : &:r0_38, r0_37
# 45| valnum = r0_37
# 46| r0_40(glval<int>) = VariableAddress[x] :
# 45| m0_40(int) = Store : &:r0_39, r0_38
# 45| valnum = r0_38
# 46| r0_41(glval<int>) = VariableAddress[x] :
# 46| valnum = r0_9
# 46| r0_41(int) = Load : &:r0_40, m0_39
# 46| valnum = r0_37
# 46| r0_42(glval<int>) = VariableAddress[y] :
# 46| r0_42(int) = Load : &:r0_41, m0_40
# 46| valnum = r0_38
# 46| r0_43(glval<int>) = VariableAddress[y] :
# 46| valnum = r0_11
# 46| m0_43(int) = Store : &:r0_42, r0_41
# 46| valnum = r0_37
# 47| v0_44(void) = NoOp :
# 39| r0_45(glval<int>) = VariableAddress[#return] :
# 46| m0_44(int) = Store : &:r0_43, r0_42
# 46| valnum = r0_38
# 47| v0_45(void) = NoOp :
# 39| r0_46(glval<int>) = VariableAddress[#return] :
# 39| valnum = unique
# 39| v0_46(void) = ReturnValue : &:r0_45
# 39| v0_47(void) = UnmodeledUse : mu*
# 39| v0_48(void) = AliasedUse : ~m0_29
# 39| v0_49(void) = ExitFunction :
# 39| v0_47(void) = ReturnValue : &:r0_46
# 39| v0_48(void) = UnmodeledUse : mu*
# 39| v0_49(void) = AliasedUse : ~m0_30
# 39| v0_50(void) = ExitFunction :
# 49| unsigned int my_strspn(char const*, char const*)
# 49| Block 0
@@ -677,84 +679,86 @@ test.cpp:
# 92| valnum = r0_3
# 92| m0_6(int) = Store : &:r0_5, r0_4
# 92| valnum = r0_4
# 92| m0_7(int) = Store : &:r0_3, r0_4
# 92| r0_7(int) = CopyValue : r0_4
# 92| valnum = r0_4
# 93| r0_8(glval<int>) = VariableAddress[#return] :
# 93| valnum = r0_8
# 93| r0_9(glval<int>) = VariableAddress[x] :
# 92| m0_8(int) = Store : &:r0_3, r0_7
# 92| valnum = r0_4
# 93| r0_9(glval<int>) = VariableAddress[#return] :
# 93| valnum = r0_9
# 93| r0_10(glval<int>) = VariableAddress[x] :
# 93| valnum = r0_3
# 93| r0_10(int) = Load : &:r0_9, m0_7
# 93| r0_11(int) = Load : &:r0_10, m0_8
# 93| valnum = r0_4
# 93| m0_11(int) = Store : &:r0_8, r0_10
# 93| m0_12(int) = Store : &:r0_9, r0_11
# 93| valnum = r0_4
# 91| r0_12(glval<int>) = VariableAddress[#return] :
# 91| valnum = r0_8
# 91| v0_13(void) = ReturnValue : &:r0_12, m0_11
# 91| v0_14(void) = UnmodeledUse : mu*
# 91| v0_15(void) = AliasedUse : ~m0_1
# 91| v0_16(void) = ExitFunction :
# 91| r0_13(glval<int>) = VariableAddress[#return] :
# 91| valnum = r0_9
# 91| v0_14(void) = ReturnValue : &:r0_13, m0_12
# 91| v0_15(void) = UnmodeledUse : mu*
# 91| v0_16(void) = AliasedUse : ~m0_1
# 91| v0_17(void) = ExitFunction :
# 104| int inheritanceConversions(Derived*)
# 104| Block 0
# 104| v0_0(void) = EnterFunction :
# 104| m0_1(unknown) = AliasedDefinition :
# 104| v0_0(void) = EnterFunction :
# 104| m0_1(unknown) = AliasedDefinition :
# 104| valnum = unique
# 104| mu0_2(unknown) = UnmodeledDefinition :
# 104| mu0_2(unknown) = UnmodeledDefinition :
# 104| valnum = unique
# 104| r0_3(glval<Derived *>) = VariableAddress[pd] :
# 104| r0_3(glval<Derived *>) = VariableAddress[pd] :
# 104| valnum = r0_3
# 104| m0_4(Derived *) = InitializeParameter[pd] : &:r0_3
# 104| m0_4(Derived *) = InitializeParameter[pd] : &:r0_3
# 104| valnum = m0_4
# 105| r0_5(glval<int>) = VariableAddress[x] :
# 105| r0_5(glval<int>) = VariableAddress[x] :
# 105| valnum = unique
# 105| r0_6(glval<Derived *>) = VariableAddress[pd] :
# 105| r0_6(glval<Derived *>) = VariableAddress[pd] :
# 105| valnum = r0_3
# 105| r0_7(Derived *) = Load : &:r0_6, m0_4
# 105| r0_7(Derived *) = Load : &:r0_6, m0_4
# 105| valnum = m0_4
# 105| r0_8(Base *) = ConvertToBase[Derived : Base] : r0_7
# 105| r0_8(Base *) = ConvertToNonVirtualBase[Derived : Base] : r0_7
# 105| valnum = r0_8
# 105| r0_9(glval<int>) = FieldAddress[b] : r0_8
# 105| r0_9(glval<int>) = FieldAddress[b] : r0_8
# 105| valnum = r0_9
# 105| r0_10(int) = Load : &:r0_9, ~m0_1
# 105| r0_10(int) = Load : &:r0_9, ~m0_1
# 105| valnum = r0_10
# 105| m0_11(int) = Store : &:r0_5, r0_10
# 105| m0_11(int) = Store : &:r0_5, r0_10
# 105| valnum = r0_10
# 106| r0_12(glval<Base *>) = VariableAddress[pb] :
# 106| r0_12(glval<Base *>) = VariableAddress[pb] :
# 106| valnum = r0_12
# 106| r0_13(glval<Derived *>) = VariableAddress[pd] :
# 106| r0_13(glval<Derived *>) = VariableAddress[pd] :
# 106| valnum = r0_3
# 106| r0_14(Derived *) = Load : &:r0_13, m0_4
# 106| r0_14(Derived *) = Load : &:r0_13, m0_4
# 106| valnum = m0_4
# 106| r0_15(Base *) = ConvertToBase[Derived : Base] : r0_14
# 106| r0_15(Base *) = ConvertToNonVirtualBase[Derived : Base] : r0_14
# 106| valnum = r0_8
# 106| m0_16(Base *) = Store : &:r0_12, r0_15
# 106| m0_16(Base *) = Store : &:r0_12, r0_15
# 106| valnum = r0_8
# 107| r0_17(glval<int>) = VariableAddress[y] :
# 107| r0_17(glval<int>) = VariableAddress[y] :
# 107| valnum = r0_17
# 107| r0_18(glval<Base *>) = VariableAddress[pb] :
# 107| r0_18(glval<Base *>) = VariableAddress[pb] :
# 107| valnum = r0_12
# 107| r0_19(Base *) = Load : &:r0_18, m0_16
# 107| r0_19(Base *) = Load : &:r0_18, m0_16
# 107| valnum = r0_8
# 107| r0_20(glval<int>) = FieldAddress[b] : r0_19
# 107| r0_20(glval<int>) = FieldAddress[b] : r0_19
# 107| valnum = r0_9
# 107| r0_21(int) = Load : &:r0_20, ~m0_1
# 107| r0_21(int) = Load : &:r0_20, ~m0_1
# 107| valnum = r0_21
# 107| m0_22(int) = Store : &:r0_17, r0_21
# 107| m0_22(int) = Store : &:r0_17, r0_21
# 107| valnum = r0_21
# 109| r0_23(glval<int>) = VariableAddress[#return] :
# 109| r0_23(glval<int>) = VariableAddress[#return] :
# 109| valnum = r0_23
# 109| r0_24(glval<int>) = VariableAddress[y] :
# 109| r0_24(glval<int>) = VariableAddress[y] :
# 109| valnum = r0_17
# 109| r0_25(int) = Load : &:r0_24, m0_22
# 109| r0_25(int) = Load : &:r0_24, m0_22
# 109| valnum = r0_21
# 109| m0_26(int) = Store : &:r0_23, r0_25
# 109| m0_26(int) = Store : &:r0_23, r0_25
# 109| valnum = r0_21
# 104| r0_27(glval<int>) = VariableAddress[#return] :
# 104| r0_27(glval<int>) = VariableAddress[#return] :
# 104| valnum = r0_23
# 104| v0_28(void) = ReturnValue : &:r0_27, m0_26
# 104| v0_29(void) = UnmodeledUse : mu*
# 104| v0_30(void) = AliasedUse : ~m0_1
# 104| v0_31(void) = ExitFunction :
# 104| v0_28(void) = ReturnValue : &:r0_27, m0_26
# 104| v0_29(void) = UnmodeledUse : mu*
# 104| v0_30(void) = AliasedUse : ~m0_1
# 104| v0_31(void) = ExitFunction :
# 112| void test06()
# 112| Block 0

View File

@@ -1 +1,3 @@
| SignedOverflowCheck.cpp:35:9:35:23 | ... < ... | Bad overflow check. |
| SignedOverflowCheck.cpp:113:12:113:66 | ... < ... | Bad overflow check. |
| test.cpp:3:11:3:19 | ... < ... | Bad overflow check. |

View File

@@ -1,3 +1,4 @@
| templates.cpp:17:5:17:25 | ... < ... | Self comparison. |
| test.cpp:13:11:13:21 | ... == ... | Self comparison. |
| test.cpp:79:11:79:32 | ... == ... | Self comparison. |
| test.cpp:83:10:83:15 | ... == ... | Self comparison. |

View File

@@ -0,0 +1,130 @@
// Signed-comparison tests
/* 1. Signed-signed comparison. The semantics are undefined. */
bool cannotHoldAnother8(int n1) {
// clang 8.0.0 -O2: deleted (silently)
// gcc 9.2 -O2: deleted (silently)
// msvc 19.22 /O2: not deleted
return n1 + 8 < n1; // BAD
}
/* 2. Signed comparison with a narrower unsigned type. The narrower
type gets promoted to the (signed) larger type, and so the
semantics are undefined. */
bool cannotHoldAnotherUShort(int n1, unsigned short delta) {
// clang 8.0.0 -O2: deleted (silently)
// gcc 9.2 -O2: deleted (silently)
// msvc 19.22 /O2: not deleted
return n1 + delta < n1; // BAD
}
/* 3. Signed comparison with a non-narrower unsigned type. The
signed type gets promoted to (a possibly wider) unsigned type,
and the resulting comparison is unsigned. */
bool cannotHoldAnotherUInt(int n1, unsigned int delta) {
// clang 8.0.0 -O2: not deleted
// gcc 9.2 -O2: not deleted
// msvc 19.22 /O2: not deleted
return n1 + delta < n1; // GOOD
}
bool shortShort1(unsigned short n1, unsigned short delta) {
// BAD [BadAdditionOverflowCheck.ql]
// GOOD [SigneOverflowCheck.ql]: Test always fails, but will never overflow.
return n1 + delta < n1;
}
bool shortShort2(unsigned short n1, unsigned short delta) {
// clang 8.0.0 -O2: not deleted
// gcc 9.2 -O2: not deleted
// msvc 19.22 /O2: not deleted
return (unsigned short)(n1 + delta) < n1; // GOOD
}
/* Distinguish `varname` from `ptr->varname` and `obj.varname` */
struct N {
int n1;
} n, *np;
bool shortStruct1(unsigned short n1, unsigned short delta) {
return np->n1 + delta < n1; // GOOD
}
bool shortStruct1a(unsigned short n1, unsigned short delta) {
return n1 + delta < n.n1; // GOOD
}
bool shortStruct2(unsigned short n1, unsigned short delta) {
return (unsigned short)(n1 + delta) < n.n1; // GOOD
}
struct se {
int xPos;
short yPos;
short xSize;
short ySize;
};
extern se *getSo(void);
bool func1(se *so) {
se *o = getSo();
if (so->xPos + so->xSize < so->xPos // BAD
|| so->xPos > o->xPos + o->xSize) { // GOOD
// clang 8.0.0 -O2: not deleted
// gcc 9.2 -O2: not deleted
// msvc 19.22 /O2: not deleted
return false;
}
return true;
}
bool checkOverflow3(unsigned int a, unsigned short b) {
return (a + b < a); // GOOD
}
struct C {
unsigned int length;
};
int checkOverflow4(unsigned int ioff, C c) {
// not deleted by gcc or clang
if ((int)(ioff + c.length) < (int)ioff) return 0; // GOOD
return 1;
}
int overflow12(int n) {
// not deleted by gcc or clang
return (n + 32 <= (unsigned)n? -1: 1); // BAD: n + 32 can overflow
}
bool multipleCasts(char x) {
// BAD [UNDETECTED - BadAdditionOverflowCheck.ql]
// GOOD [SigneOverflowCheck.ql]: Test always fails, but will never overflow.
return (int)(unsigned short)x + 2 < (int)(unsigned short)x; // GOOD: cannot overflow
}
bool multipleCasts2(char x) {
// BAD [BadAdditionOverflowCheck.ql]
// GOOD [SigneOverflowCheck.ql]: Test always fails, but will never overflow.
return (int)(unsigned short)(x + '1') < (int)(unsigned short)x;
}
int does_it_overflow(int n1, unsigned short delta) {
return n1 + (unsigned)delta < n1; // GOOD: everything converted to unsigned
}
int overflow12b(int n) {
// not deleted by gcc or clang
return ((unsigned)(n + 32) <= (unsigned)n? -1: 1); // BAD: n + 32 may overflow
}
#define MACRO(E1, E2) (E1) <= (E2)? -1: 1
int overflow12_macro(int n) {
return MACRO((unsigned)(n + 32), (unsigned)n); // GOOD: inside a macro expansion
}

View File

@@ -0,0 +1,5 @@
| SignedOverflowCheck.cpp:8:12:8:22 | ... < ... | Testing for signed overflow may produce undefined results. |
| SignedOverflowCheck.cpp:18:12:18:26 | ... < ... | Testing for signed overflow may produce undefined results. |
| SignedOverflowCheck.cpp:73:6:73:36 | ... < ... | Testing for signed overflow may produce undefined results. |
| SignedOverflowCheck.cpp:99:10:99:30 | ... <= ... | Testing for signed overflow may produce undefined results. |
| SignedOverflowCheck.cpp:122:10:122:42 | ... <= ... | Testing for signed overflow may produce undefined results. |

View File

@@ -0,0 +1 @@
Likely Bugs/Arithmetic/SignedOverflowCheck.ql

View File

@@ -0,0 +1,22 @@
struct C1 {
static const int value = 5;
};
struct C2 {
static const int value = 6;
};
template<typename T1, typename T2>
bool compareValues() {
// Not all instantiations have T1 and T2 equal. Even if that's the case for
// all instantiations in the program, there could still be more such
// instantiations outside.
return
T1::value < T2::value || // GOOD
T1::value < T1::value || // BAD [NOT DETECTED]
C1::value < C1::value ; // BAD
}
bool callCompareValues() {
return compareValues<C1, C2> || compareValues<C1, C1>();
}

View File

@@ -1,11 +1,11 @@
// Test for BadAdditionOverflowCheck.
bool checkOverflow1(unsigned short a, unsigned short b) {
return (a + b < a); // BAD: a + b is automatically promoted to int.
return (a + b < a); // BAD: comparison always false (due to promotion).
}
// Test for BadAdditionOverflowCheck.
bool checkOverflow2(unsigned short a, unsigned short b) {
return ((unsigned short)(a + b) < a); // GOOD: explicit cast
return ((unsigned short)(a + b) < a); // GOOD
}
// Test for PointlessSelfComparison.

View File

@@ -0,0 +1,19 @@
__attribute__((format(printf, 1, 3)))
void myMultiplyDefinedPrintf(const char *format, const char *extraArg, ...)
{
// ...
}
__attribute__((format(printf, 1, 3)))
void myMultiplyDefinedPrintf2(const char *format, const char *extraArg, ...);
char *getString();
void test_custom_printf1()
{
myMultiplyDefinedPrintf("string", getString()); // GOOD
myMultiplyDefinedPrintf(getString(), "string"); // BAD [NOT DETECTED]
myMultiplyDefinedPrintf2("string", getString()); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
myMultiplyDefinedPrintf2(getString(), "string"); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
}

View File

@@ -0,0 +1,16 @@
__attribute__((format(printf, 2, 3)))
void myMultiplyDefinedPrintf(const char *extraArg, const char *format, ...); // this declaration does not match the definition
__attribute__((format(printf, 2, 3)))
void myMultiplyDefinedPrintf2(const char *extraArg, const char *format, ...);
char *getString();
void test_custom_printf2(char *string)
{
myMultiplyDefinedPrintf("string", getString()); // GOOD
myMultiplyDefinedPrintf(getString(), "string"); // BAD [NOT DETECTED]
myMultiplyDefinedPrintf2("string", getString()); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
myMultiplyDefinedPrintf2(getString(), "string"); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
}

View File

@@ -16,6 +16,43 @@
| printf1.h:114:18:114:18 | d | This argument should be of type 'long double' but is of type 'double' |
| printf1.h:147:19:147:19 | i | This argument should be of type 'long long' but is of type 'int' |
| printf1.h:148:19:148:20 | ui | This argument should be of type 'unsigned long long' but is of type 'unsigned int' |
| printf1.h:160:18:160:18 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:161:21:161:21 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:167:17:167:17 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:168:18:168:18 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:169:19:169:19 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:174:17:174:17 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:175:18:175:18 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:176:19:176:19 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:180:17:180:17 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:181:20:181:20 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:183:18:183:18 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:184:21:184:21 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:186:19:186:19 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:187:22:187:22 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:189:19:189:19 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:190:22:190:22 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:192:19:192:19 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:193:22:193:22 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:194:25:194:25 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:198:24:198:24 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:199:21:199:21 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:202:26:202:26 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:203:23:203:23 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:206:25:206:25 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:207:22:207:22 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:210:26:210:26 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:211:23:211:23 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:214:28:214:28 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:215:28:215:28 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:216:25:216:25 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:221:18:221:18 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:222:20:222:20 | s | This argument should be of type 'int' but is of type 'char *' |
| printf1.h:225:23:225:23 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:228:24:228:24 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:231:25:231:25 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:234:25:234:25 | i | This argument should be of type 'char *' but is of type 'int' |
| printf1.h:235:22:235:22 | s | This argument should be of type 'int' but is of type 'char *' |
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |
| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' |
| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' |

View File

@@ -0,0 +1,16 @@
__attribute__((format(printf, 1, 3)))
void myMultiplyDefinedPrintf(const char *format, const char *extraArg, ...)
{
// ...
}
__attribute__((format(printf, 1, 3)))
void myMultiplyDefinedPrintf2(const char *format, const char *extraArg, ...);
void test_custom_printf1()
{
myMultiplyDefinedPrintf("%i", "%f", 1); // GOOD
myMultiplyDefinedPrintf("%i", "%f", 1.0f); // BAD [NOT DETECTED]
myMultiplyDefinedPrintf2("%i", "%f", 1); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
myMultiplyDefinedPrintf2("%i", "%f", 1.0f); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
}

View File

@@ -0,0 +1,14 @@
__attribute__((format(printf, 2, 3)))
void myMultiplyDefinedPrintf(const char *extraArg, const char *format, ...); // this declaration does not match the definition
__attribute__((format(printf, 2, 3)))
void myMultiplyDefinedPrintf2(const char *extraArg, const char *format, ...);
void test_custom_printf2()
{
myMultiplyDefinedPrintf("%i", "%f", 1); // GOOD
myMultiplyDefinedPrintf("%i", "%f", 1.0f); // BAD [NOT DETECTED]
myMultiplyDefinedPrintf2("%i", "%f", 1); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
myMultiplyDefinedPrintf2("%i", "%f", 1.0f); // GOOD (we can't tell which declaration is correct so we have to assume this is OK)
}

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