mirror of
https://github.com/github/codeql.git
synced 2026-07-20 18:58:36 +02:00
Merge branch 'master' into pointer-wraparound-query
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
bool foo(int n1, unsigned short delta) {
|
||||
return n1 + delta < n1; // BAD
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
bool bar(unsigned short n1, unsigned short delta) {
|
||||
// NB: Comparison is always false
|
||||
return n1 + delta < n1; // GOOD (but misleading)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#include <limits.h>
|
||||
bool foo(int n1, unsigned short delta) {
|
||||
return n1 > INT_MAX - delta; // GOOD
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
bool bar(unsigned short n1, unsigned short delta) {
|
||||
return (unsigned short)(n1 + delta) < n1; // GOOD
|
||||
}
|
||||
115
cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp
Normal file
115
cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp
Normal 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 < 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 < i</code>,
|
||||
it is possible to rewrite it as <code>(unsigned short)(i + delta) < 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 < i</code>,
|
||||
it is also possible to rewrite it as <code>USHORT_MAX - delta</code>. It must be true
|
||||
that <code>delta > 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 < i</code>,
|
||||
it is possible to rewrite it as <code>INT_MAX - delta</code>. It must be true
|
||||
that <code>delta > 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 < i</code>,
|
||||
it is also possible to rewrite it as <code>(unsigned)i + delta < i</code>.
|
||||
Note that program semantics are affected by this change.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given <code>int i, delta</code> and <code>i + delta < i</code>,
|
||||
it is also possible to rewrite it as <code>unsigned int i, delta</code> and
|
||||
<code>i + delta < 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 < 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>
|
||||
31
cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
Normal file
31
cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
Normal 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."
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'. */
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() |
|
||||
|
||||
@@ -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 = ""
|
||||
}
|
||||
|
||||
@@ -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(_)
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(_, _)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() }
|
||||
|
||||
/**
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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
@@ -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]
|
||||
}
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
@@ -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 :
|
||||
|
||||
@@ -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`.
|
||||
}
|
||||
|
||||
@@ -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 :
|
||||
|
||||
@@ -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> |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 | |
|
||||
@@ -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
|
||||
@@ -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*) |
|
||||
|
||||
@@ -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 | |
|
||||
@@ -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), ", ")
|
||||
@@ -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);
|
||||
@@ -0,0 +1,2 @@
|
||||
| test.cpp:13:15:13:15 | k |
|
||||
| test.cpp:14:7:14:9 | foo |
|
||||
@@ -0,0 +1,4 @@
|
||||
import cpp
|
||||
|
||||
from Literal l
|
||||
select l
|
||||
@@ -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) |
|
||||
|
||||
@@ -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 && |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
template <int i>
|
||||
class Int { };
|
||||
|
||||
Int<10> i;
|
||||
@@ -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 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import cpp
|
||||
|
||||
from Class c
|
||||
select c, c.getATemplateArgumentKind(), c.getATemplateArgument()
|
||||
@@ -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>(); }
|
||||
@@ -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 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import cpp
|
||||
|
||||
from Function f
|
||||
select f, f.getATemplateArgumentKind(), f.getATemplateArgument()
|
||||
@@ -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;
|
||||
|
||||
@@ -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 |
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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. |
|
||||
|
||||
@@ -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. |
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Arithmetic/SignedOverflowCheck.ql
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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 *' |
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user