mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Merge branch 'master' into users/raulga/c6276
This commit is contained in:
@@ -119,7 +119,7 @@ class CommentBlock extends Comment {
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||
this.lastComment().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn)
|
||||
this.lastComment().getLocation().hasLocationInfo(_, _, _, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Semmle C/C++ Default Queries
|
||||
Bundle-SymbolicName: com.semmle.plugin.semmlecode.cpp.queries;singleton:=true
|
||||
Bundle-Version: 1.18.0.qualifier
|
||||
Bundle-Version: 1.18.1.qualifier
|
||||
Bundle-Vendor: Semmle Ltd.
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.semmle.plugin.qdt.ui;bundle-version="[1.18.0.qualifier,1.18.0.qualifier]"
|
||||
Require-Bundle: com.semmle.plugin.qdt.ui;bundle-version="[1.18.1.qualifier,1.18.1.qualifier]"
|
||||
|
||||
@@ -13,18 +13,19 @@
|
||||
import cpp
|
||||
import IncorrectPointerScalingCommon
|
||||
|
||||
private predicate isCharPtrExpr(Expr e) {
|
||||
private predicate isCharSzPtrExpr(Expr e) {
|
||||
exists (PointerType pt
|
||||
| pt = e.getFullyConverted().getUnderlyingType()
|
||||
| pt.getBaseType().getUnspecifiedType() instanceof CharType)
|
||||
| pt.getBaseType().getUnspecifiedType() instanceof CharType
|
||||
or pt.getBaseType().getUnspecifiedType() instanceof VoidType)
|
||||
}
|
||||
|
||||
from Expr sizeofExpr, Expr e
|
||||
where
|
||||
// If we see an addWithSizeof then we expect the type of
|
||||
// the pointer expression to be char*. Otherwise it is probably
|
||||
// a mistake.
|
||||
addWithSizeof(e, sizeofExpr, _) and not isCharPtrExpr(e)
|
||||
// the pointer expression to be char* or void*. Otherwise it
|
||||
// is probably a mistake.
|
||||
addWithSizeof(e, sizeofExpr, _) and not isCharSzPtrExpr(e)
|
||||
select
|
||||
sizeofExpr,
|
||||
"Suspicious sizeof offset in a pointer arithmetic expression. " +
|
||||
|
||||
@@ -102,7 +102,8 @@ private predicate constructorCallStartLoc(ConstructorCall cc, File f, int line,
|
||||
|
||||
/**
|
||||
* Holds if `f`, `line`, `column` indicate the start character
|
||||
* of `tm`, which mentions `t`.
|
||||
* of `tm`, which mentions `t`. Type mentions for instantiations
|
||||
* are filtered out.
|
||||
*/
|
||||
private predicate typeMentionStartLoc(TypeMention tm, Type t, File f, int line, int column) {
|
||||
exists(Location l |
|
||||
@@ -111,7 +112,8 @@ private predicate typeMentionStartLoc(TypeMention tm, Type t, File f, int line,
|
||||
l.getStartLine() = line and
|
||||
l.getStartColumn() = column
|
||||
) and
|
||||
t = tm.getMentionedType()
|
||||
t = tm.getMentionedType() and
|
||||
not t instanceof ClassTemplateInstantiation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,41 +2,38 @@ import semmle.code.cpp.Location
|
||||
private import semmle.code.cpp.Enclosing
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
* Get the `@element` that represents this `@element`.
|
||||
* Normally this will simply be `e`, but sometimes it is not.
|
||||
* For example, for an incomplete struct `e` the result may be a
|
||||
* complete struct with the same name.
|
||||
*/
|
||||
private cached @element resolveElement(@element e) {
|
||||
if isClass(e)
|
||||
then result = resolveClass(e)
|
||||
else result = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `Element` that represents this `@element`.
|
||||
* Normally this will simply be a cast of `e`, but sometimes it is not.
|
||||
* For example, for an incomplete struct `e` the result may be a
|
||||
* complete struct with the same name.
|
||||
*/
|
||||
pragma[inline]
|
||||
Element mkElement(@element e) {
|
||||
result = resolveElement(e)
|
||||
unresolveElement(result) = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an `@element` that resolves to the `Element`. This should
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets an `@element` that resolves to the `Element`. This should
|
||||
* normally only be called from member predicates, where `e` is not
|
||||
* `this` and you need the result for an argument to a database
|
||||
* extensional.
|
||||
* See `underlyingElement` for when `e` is `this`.
|
||||
*/
|
||||
pragma[inline]
|
||||
@element unresolveElement(Element e) {
|
||||
resolveElement(result) = e
|
||||
not result instanceof @usertype and
|
||||
result = e
|
||||
or
|
||||
e = resolveClass(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `@element` that this `Element` extends. This should normally
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets the `@element` that this `Element` extends. This should normally
|
||||
* only be called from member predicates, where `e` is `this` and you
|
||||
* need the result for an argument to a database extensional.
|
||||
* See `unresolveElement` for when `e` is not `this`.
|
||||
@@ -53,10 +50,6 @@ Element mkElement(@element e) {
|
||||
* `getLocation`, or `hasLocationInfo`.
|
||||
*/
|
||||
class ElementBase extends @element {
|
||||
ElementBase() {
|
||||
this = resolveElement(_)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
@@ -294,13 +294,13 @@ class AttributeArgument extends Element, @attribute_arg {
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
if exists (@attribute_arg_empty self | mkElement(self) = this)
|
||||
if exists (@attribute_arg_empty self | self = underlyingElement(this))
|
||||
then result = "empty argument"
|
||||
else exists (string prefix, string tail
|
||||
| (if exists(getName())
|
||||
then prefix = getName() + "="
|
||||
else prefix = "") and
|
||||
(if exists (@attribute_arg_type self | mkElement(self) = this)
|
||||
(if exists (@attribute_arg_type self | self = underlyingElement(this))
|
||||
then tail = getValueType().getName()
|
||||
else tail = getValueText()) and
|
||||
result = prefix + tail)
|
||||
|
||||
@@ -7,6 +7,8 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* A C/C++ type.
|
||||
*/
|
||||
class Type extends Locatable, @type {
|
||||
Type() { isType(underlyingElement(this)) }
|
||||
|
||||
/**
|
||||
* Gets the name of this type.
|
||||
*/
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/**
|
||||
* A library for working with XML files and their content.
|
||||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
/** An XML element that has a location. */
|
||||
abstract class XMLLocatable extends @xmllocatable {
|
||||
/** The source location for this element. */
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { xmllocations(this,result) }
|
||||
|
||||
/**
|
||||
* Whether this element has the specified location information,
|
||||
* Holds if this element has the specified location information,
|
||||
* including file path, start line, start column, end line and end column.
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||
@@ -20,7 +20,7 @@ abstract class XMLLocatable extends @xmllocatable {
|
||||
)
|
||||
}
|
||||
|
||||
/** A printable representation of this element. */
|
||||
/** Gets a printable representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
@@ -30,46 +30,49 @@ abstract class XMLLocatable extends @xmllocatable {
|
||||
*/
|
||||
class XMLParent extends @xmlparent {
|
||||
/**
|
||||
* A printable representation of this XML parent.
|
||||
* Gets a printable representation of this XML parent.
|
||||
* (Intended to be overridden in subclasses.)
|
||||
*/
|
||||
abstract string getName();
|
||||
|
||||
/** The file to which this XML parent belongs. */
|
||||
/** Gets the file to which this XML parent belongs. */
|
||||
XMLFile getFile() { result = this or xmlElements(this,_,_,_,result) }
|
||||
|
||||
/** The child element at a specified index of this XML parent. */
|
||||
/** Gets the child element at a specified index of this XML parent. */
|
||||
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
||||
|
||||
/** A child element of this XML parent. */
|
||||
/** Gets a child element of this XML parent. */
|
||||
XMLElement getAChild() { xmlElements(result,_,this,_,_) }
|
||||
|
||||
/** A child element of this XML parent with the given `name`. */
|
||||
/** Gets a child element of this XML parent with the given `name`. */
|
||||
XMLElement getAChild(string name) { xmlElements(result,_,this,_,_) and result.hasName(name) }
|
||||
|
||||
/** A comment that is a child of this XML parent. */
|
||||
/** Gets a comment that is a child of this XML parent. */
|
||||
XMLComment getAComment() { xmlComments(result,_,this,_) }
|
||||
|
||||
/** A character sequence that is a child of this XML parent. */
|
||||
/** Gets a character sequence that is a child of this XML parent. */
|
||||
XMLCharacters getACharactersSet() { xmlChars(result,_,this,_,_,_) }
|
||||
|
||||
/** The depth in the tree. (Overridden in XMLElement.) */
|
||||
/** Gets the depth in the tree. (Overridden in XMLElement.) */
|
||||
int getDepth() { result = 0 }
|
||||
|
||||
/** The number of child XML elements of this XML parent. */
|
||||
/** Gets the number of child XML elements of this XML parent. */
|
||||
int getNumberOfChildren() {
|
||||
result = count(XMLElement e | xmlElements(e,_,this,_,_))
|
||||
}
|
||||
|
||||
/** The number of places in the body of this XML parent where text occurs. */
|
||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||
int getNumberOfCharacterSets() {
|
||||
result = count(int pos | xmlChars(_,_,this,pos,_,_))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Internal.
|
||||
*
|
||||
* Append the character sequences of this XML parent from left to right, separated by a space,
|
||||
* up to a specified (zero-based) index.
|
||||
*/
|
||||
deprecated
|
||||
string charsSetUpTo(int n) {
|
||||
(n = 0 and xmlChars(_,result,this,0,_,_)) or
|
||||
(n > 0 and exists(string chars | xmlChars(_,chars,this,n,_,_) |
|
||||
@@ -78,18 +81,15 @@ class XMLParent extends @xmlparent {
|
||||
|
||||
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
|
||||
string allCharactersString() {
|
||||
exists(int n | n = this.getNumberOfCharacterSets() |
|
||||
(n = 0 and result = "") or
|
||||
(n > 0 and result = this.charsSetUpTo(n-1))
|
||||
)
|
||||
result = concat(string chars, int pos | xmlChars(_, chars, this, pos, _, _) | chars, " " order by pos)
|
||||
}
|
||||
|
||||
/** The text value contained in this XML parent. */
|
||||
/** Gets the text value contained in this XML parent. */
|
||||
string getTextValue() {
|
||||
result = allCharactersString()
|
||||
}
|
||||
|
||||
/** A printable representation of this XML parent. */
|
||||
/** Gets a printable representation of this XML parent. */
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
@@ -99,54 +99,54 @@ class XMLFile extends XMLParent, File {
|
||||
xmlEncoding(this,_)
|
||||
}
|
||||
|
||||
/** A printable representation of this XML file. */
|
||||
/** Gets a printable representation of this XML file. */
|
||||
override
|
||||
string toString() { result = XMLParent.super.toString() }
|
||||
|
||||
/** The name of this XML file. */
|
||||
/** Gets the name of this XML file. */
|
||||
override
|
||||
string getName() { files(this,result,_,_,_) }
|
||||
|
||||
/** The path of this XML file. */
|
||||
/** Gets the path of this XML file. */
|
||||
string getPath() { files(this,_,result,_,_) }
|
||||
|
||||
/** The path of the folder that contains this XML file. */
|
||||
/** Gets the path of the folder that contains this XML file. */
|
||||
string getFolder() {
|
||||
result = this.getPath().substring(0, this.getPath().length()-this.getName().length())
|
||||
}
|
||||
|
||||
/** The encoding of this XML file. */
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this,result) }
|
||||
|
||||
/** The XML file itself. */
|
||||
/** Gets the XML file itself. */
|
||||
override
|
||||
XMLFile getFile() { result = this }
|
||||
|
||||
/** A top-most element in an XML file. */
|
||||
/** Gets a top-most element in an XML file. */
|
||||
XMLElement getARootElement() { result = this.getAChild() }
|
||||
|
||||
/** A DTD associated with this XML file. */
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XMLDTD getADTD() { xmlDTDs(result,_,_,_,this) }
|
||||
}
|
||||
|
||||
/** A "Document Type Definition" of an XML file. */
|
||||
class XMLDTD extends @xmldtd {
|
||||
/** The name of the root element of this DTD. */
|
||||
/** Gets the name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this,result,_,_,_) }
|
||||
|
||||
/** The public ID of this DTD. */
|
||||
/** Gets the public ID of this DTD. */
|
||||
string getPublicId() { xmlDTDs(this,_,result,_,_) }
|
||||
|
||||
/** The system ID of this DTD. */
|
||||
/** Gets the system ID of this DTD. */
|
||||
string getSystemId() { xmlDTDs(this,_,_,result,_) }
|
||||
|
||||
/** Whether this DTD is public. */
|
||||
/** Holds if this DTD is public. */
|
||||
predicate isPublic() { not xmlDTDs(this,_,"",_,_) }
|
||||
|
||||
/** The parent of this DTD. */
|
||||
/** Gets the parent of this DTD. */
|
||||
XMLParent getParent() { xmlDTDs(this,_,_,_,result) }
|
||||
|
||||
/** A printable representation of this DTD. */
|
||||
/** Gets a printable representation of this DTD. */
|
||||
string toString() {
|
||||
(this.isPublic() and result = this.getRoot() + " PUBLIC '" +
|
||||
this.getPublicId() + "' '" +
|
||||
@@ -159,92 +159,92 @@ class XMLDTD extends @xmldtd {
|
||||
|
||||
/** An XML tag in an XML file. */
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
/** Whether this XML element has the given `name`. */
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = getName() }
|
||||
|
||||
/** The name of this XML element. */
|
||||
/** Gets the name of this XML element. */
|
||||
override
|
||||
string getName() { xmlElements(this,result,_,_,_) }
|
||||
|
||||
/** The XML file in which this XML element occurs. */
|
||||
/** Gets the XML file in which this XML element occurs. */
|
||||
override
|
||||
XMLFile getFile() { xmlElements(this,_,_,_,result) }
|
||||
|
||||
/** The parent of this XML element. */
|
||||
/** Gets the parent of this XML element. */
|
||||
XMLParent getParent() { xmlElements(this,_,result,_,_) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getIndex() { xmlElements(this, _, _, result, _) }
|
||||
|
||||
/** Whether this XML element has a namespace. */
|
||||
/** Holds if this XML element has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
|
||||
/** The namespace of this XML element, if any. */
|
||||
/** Gets the namespace of this XML element, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getElementPositionIndex() { xmlElements(this,_,_,result,_) }
|
||||
|
||||
/** The depth of this element within the XML file tree structure. */
|
||||
/** Gets the depth of this element within the XML file tree structure. */
|
||||
override
|
||||
int getDepth() { result = this.getParent().getDepth() + 1 }
|
||||
|
||||
/** An XML attribute of this XML element. */
|
||||
/** Gets an XML attribute of this XML element. */
|
||||
XMLAttribute getAnAttribute() { result.getElement() = this }
|
||||
|
||||
/** The attribute with the specified `name`, if any. */
|
||||
/** Gets the attribute with the specified `name`, if any. */
|
||||
XMLAttribute getAttribute(string name) {
|
||||
result.getElement() = this and result.getName() = name
|
||||
}
|
||||
|
||||
/** Whether this XML element has an attribute with the specified `name`. */
|
||||
/** Holds if this XML element has an attribute with the specified `name`. */
|
||||
predicate hasAttribute(string name) {
|
||||
exists(XMLAttribute a| a = this.getAttribute(name))
|
||||
}
|
||||
|
||||
/** The value of the attribute with the specified `name`, if any. */
|
||||
/** Gets the value of the attribute with the specified `name`, if any. */
|
||||
string getAttributeValue(string name) {
|
||||
result = this.getAttribute(name).getValue()
|
||||
}
|
||||
|
||||
/** A printable representation of this XML element. */
|
||||
/** Gets a printable representation of this XML element. */
|
||||
override
|
||||
string toString() { result = XMLParent.super.toString() }
|
||||
}
|
||||
|
||||
/** An attribute that occurs inside an XML element. */
|
||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
/** The name of this attribute. */
|
||||
/** Gets the name of this attribute. */
|
||||
string getName() { xmlAttrs(this,_,result,_,_,_) }
|
||||
|
||||
/** The XML element to which this attribute belongs. */
|
||||
/** Gets the XML element to which this attribute belongs. */
|
||||
XMLElement getElement() { xmlAttrs(this,result,_,_,_,_) }
|
||||
|
||||
/** Whether this attribute has a namespace. */
|
||||
/** Holds if this attribute has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
|
||||
/** The namespace of this attribute, if any. */
|
||||
/** Gets the namespace of this attribute, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
|
||||
/** The value of this attribute. */
|
||||
/** Gets the value of this attribute. */
|
||||
string getValue() { xmlAttrs(this,_,_,result,_,_) }
|
||||
|
||||
/** A printable representation of this XML attribute. */
|
||||
/** Gets a printable representation of this XML attribute. */
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** A namespace used in an XML file */
|
||||
class XMLNamespace extends @xmlnamespace {
|
||||
/** The prefix of this namespace. */
|
||||
/** Gets the prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this,result,_,_) }
|
||||
|
||||
/** The URI of this namespace. */
|
||||
/** Gets the URI of this namespace. */
|
||||
string getURI() { xmlNs(this,_,result,_) }
|
||||
|
||||
/** Whether this namespace has no prefix. */
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
/** A printable representation of this XML namespace. */
|
||||
/** Gets a printable representation of this XML namespace. */
|
||||
string toString() {
|
||||
(this.isDefault() and result = this.getURI()) or
|
||||
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
|
||||
@@ -253,13 +253,13 @@ class XMLNamespace extends @xmlnamespace {
|
||||
|
||||
/** A comment of the form `<!-- ... -->` is an XML comment. */
|
||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
/** The text content of this XML comment. */
|
||||
/** Gets the text content of this XML comment. */
|
||||
string getText() { xmlComments(this,result,_,_) }
|
||||
|
||||
/** The parent of this XML comment. */
|
||||
/** Gets the parent of this XML comment. */
|
||||
XMLParent getParent() { xmlComments(this,_,result,_) }
|
||||
|
||||
/** A printable representation of this XML comment. */
|
||||
/** Gets a printable representation of this XML comment. */
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
@@ -268,15 +268,15 @@ class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
*/
|
||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
/** The content of this character sequence. */
|
||||
/** Gets the content of this character sequence. */
|
||||
string getCharacters() { xmlChars(this,result,_,_,_,_) }
|
||||
|
||||
/** The parent of this character sequence. */
|
||||
/** Gets the parent of this character sequence. */
|
||||
XMLParent getParent() { xmlChars(this,_,result,_,_,_) }
|
||||
|
||||
/** Whether this character sequence is CDATA. */
|
||||
/** Holds if this character sequence is CDATA. */
|
||||
predicate isCDATA() { xmlChars(this,_,_,_,1,_) }
|
||||
|
||||
/** A printable representation of this XML character sequence. */
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
||||
485
cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll
Normal file
485
cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll
Normal file
@@ -0,0 +1,485 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* A Boolean condition in the AST that guards one or more basic blocks. This includes
|
||||
* operands of logical operators but not switch statements.
|
||||
*/
|
||||
class GuardCondition extends Expr {
|
||||
GuardCondition() {
|
||||
exists(IRGuardCondition ir | this = ir.getUnconvertedResultExpression())
|
||||
or
|
||||
// no binary operators in the IR
|
||||
exists(GuardCondition gc |
|
||||
this.(BinaryLogicalOperation).getAnOperand()= gc
|
||||
)
|
||||
or
|
||||
// the IR short-circuits if(!x)
|
||||
(
|
||||
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
|
||||
not exists (Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAST())
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`.
|
||||
*
|
||||
* Illustration:
|
||||
*
|
||||
* ```
|
||||
* [ (testIsTrue) ]
|
||||
* [ this ----------------succ ---- controlled ]
|
||||
* [ | | ]
|
||||
* [ (testIsFalse) | ------ ... ]
|
||||
* [ other ]
|
||||
* ```
|
||||
*
|
||||
* The predicate holds if all paths to `controlled` go via the `testIsTrue`
|
||||
* edge of the control-flow graph. In other words, the `testIsTrue` edge
|
||||
* must dominate `controlled`. This means that `controlled` must be
|
||||
* dominated by both `this` and `succ` (the target of the `testIsTrue`
|
||||
* edge). It also means that any other edge into `succ` must be a back-edge
|
||||
* from a node which is dominated by `succ`.
|
||||
*
|
||||
* The short-circuit boolean operations have slightly surprising behavior
|
||||
* here: because the operation itself only dominates one branch (due to
|
||||
* being short-circuited) then it will only control blocks dominated by the
|
||||
* true (for `&&`) or false (for `||`) branch.
|
||||
*/
|
||||
cached predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
|
||||
If `isLessThan = false` then this implies `left >= right + k`. */
|
||||
cached predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
|
||||
If `areEqual = false` then this implies `left != right + k`. */
|
||||
cached predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary logical operator in the AST that guards one or more basic blocks.
|
||||
*/
|
||||
private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
|
||||
GuardConditionFromBinaryLogicalOperator() {
|
||||
exists(GuardCondition gc |
|
||||
this.(BinaryLogicalOperation).getAnOperand()= gc
|
||||
)
|
||||
}
|
||||
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
exists (BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs
|
||||
| this = binop and
|
||||
lhs = binop.getLeftOperand() and
|
||||
rhs = binop.getRightOperand() and
|
||||
lhs.controls(controlled, testIsTrue) and
|
||||
rhs.controls(controlled, testIsTrue))
|
||||
}
|
||||
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(boolean partIsTrue, GuardCondition part |
|
||||
this.(BinaryLogicalOperation).impliesValue(part, partIsTrue, testIsTrue) |
|
||||
part.comparesLt(left, right, k, isLessThan, partIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
exists(boolean testIsTrue |
|
||||
comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate comparesEq(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(boolean partIsTrue, GuardCondition part |
|
||||
this.(BinaryLogicalOperation).impliesValue(part, partIsTrue, testIsTrue) |
|
||||
part.comparesEq(left, right, k, isLessThan, partIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
exists(boolean testIsTrue |
|
||||
comparesEq(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `!` operator in the AST that guards one or more basic blocks, and does not have a corresponding
|
||||
* IR instruction.
|
||||
*/
|
||||
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
|
||||
GuardConditionFromShortCircuitNot() {
|
||||
not exists (Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | getOperand() = ir.getAST())
|
||||
}
|
||||
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).comparesLt(left, right, k, areEqual, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).ensuresLt(left, right, k, block, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).ensuresEq(left, right, k, block, testIsTrue.booleanNot())
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A Boolean condition in the AST that guards one or more basic blocks and has a corresponding IR
|
||||
* instruction.
|
||||
*/
|
||||
private class GuardConditionFromIR extends GuardCondition {
|
||||
IRGuardCondition ir;
|
||||
|
||||
GuardConditionFromIR() {
|
||||
this = ir.getUnconvertedResultExpression()
|
||||
}
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
/* This condition must determine the flow of control; that is, this
|
||||
* node must be a top-level condition. */
|
||||
this.controlsBlock(controlled, testIsTrue)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesLt(li, ri, k, isLessThan, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
|
||||
If `isLessThan = false` then this implies `left >= right + k`. */
|
||||
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
exists(Instruction li, Instruction ri, boolean testIsTrue |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesLt(li, ri, k, isLessThan, testIsTrue) and
|
||||
this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
|
||||
override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesEq(li, ri, k, areEqual, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
|
||||
If `areEqual = false` then this implies `left != right + k`. */
|
||||
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
|
||||
exists(Instruction li, Instruction ri, boolean testIsTrue |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesEq(li, ri, k, areEqual, testIsTrue)
|
||||
and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`. This helper
|
||||
* predicate does not necessarily hold for binary logical operations like
|
||||
* `&&` and `||`. See the detailed explanation on predicate `controls`.
|
||||
*/
|
||||
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
|
||||
exists(IRBlock irb |
|
||||
forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and
|
||||
irb.getAnInstruction().getAST().(ControlFlowNode).getBasicBlock() = controlled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Boolean condition in the IR that guards one or more basic blocks. This includes
|
||||
* operands of logical operators but not switch statements. Note that `&&` and `||`
|
||||
* don't have an explicit representation in the IR, and therefore will not appear as
|
||||
* IRGuardConditions.
|
||||
*/
|
||||
class IRGuardCondition extends Instruction {
|
||||
|
||||
IRGuardCondition() {
|
||||
is_condition(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`.
|
||||
*
|
||||
* Illustration:
|
||||
*
|
||||
* ```
|
||||
* [ (testIsTrue) ]
|
||||
* [ this ----------------succ ---- controlled ]
|
||||
* [ | | ]
|
||||
* [ (testIsFalse) | ------ ... ]
|
||||
* [ other ]
|
||||
* ```
|
||||
*
|
||||
* The predicate holds if all paths to `controlled` go via the `testIsTrue`
|
||||
* edge of the control-flow graph. In other words, the `testIsTrue` edge
|
||||
* must dominate `controlled`. This means that `controlled` must be
|
||||
* dominated by both `this` and `succ` (the target of the `testIsTrue`
|
||||
* edge). It also means that any other edge into `succ` must be a back-edge
|
||||
* from a node which is dominated by `succ`.
|
||||
*
|
||||
* The short-circuit boolean operations have slightly surprising behavior
|
||||
* here: because the operation itself only dominates one branch (due to
|
||||
* being short-circuited) then it will only control blocks dominated by the
|
||||
* true (for `&&`) or false (for `||`) branch.
|
||||
*/
|
||||
cached predicate controls(IRBlock controlled, boolean testIsTrue) {
|
||||
/* This condition must determine the flow of control; that is, this
|
||||
* node must be a top-level condition. */
|
||||
this.controlsBlock(controlled, testIsTrue)
|
||||
or
|
||||
exists (IRGuardCondition ne
|
||||
| this = ne.(LogicalNotInstruction).getOperand() and
|
||||
ne.controls(controlled, testIsTrue.booleanNot()))
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesLt(Instruction left, Instruction right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
compares_lt(this, left, right, k, isLessThan, testIsTrue)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
|
||||
If `isLessThan = false` then this implies `left >= right + k`. */
|
||||
cached predicate ensuresLt(Instruction left, Instruction right, int k, IRBlock block, boolean isLessThan) {
|
||||
exists(boolean testIsTrue |
|
||||
compares_lt(this, left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesEq(Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
compares_eq(this, left, right, k, areEqual, testIsTrue)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
|
||||
If `areEqual = false` then this implies `left != right + k`. */
|
||||
cached predicate ensuresEq(Instruction left, Instruction right, int k, IRBlock block, boolean areEqual) {
|
||||
exists(boolean testIsTrue |
|
||||
compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`. This helper
|
||||
* predicate does not necessarily hold for binary logical operations like
|
||||
* `&&` and `||`. See the detailed explanation on predicate `controls`.
|
||||
*/
|
||||
private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) {
|
||||
exists(IRBlock thisblock
|
||||
| thisblock.getAnInstruction() = this
|
||||
| exists(IRBlock succ, ConditionalBranchInstruction branch
|
||||
| testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor()
|
||||
or
|
||||
testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor()
|
||||
| branch.getCondition() = this and
|
||||
succ.dominates(controlled) and
|
||||
forall(IRBlock pred
|
||||
| pred.getASuccessor() = succ
|
||||
| pred = thisblock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry())))
|
||||
}
|
||||
}
|
||||
|
||||
private predicate is_condition(Instruction guard) {
|
||||
exists(ConditionalBranchInstruction branch|
|
||||
branch.getCondition() = guard
|
||||
)
|
||||
or
|
||||
exists(LogicalNotInstruction cond | is_condition(cond) and cond.getOperand() = guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
|
||||
*
|
||||
* Beware making mistaken logical implications here relating `areEqual` and `testIsTrue`.
|
||||
*/
|
||||
private predicate compares_eq(Instruction test, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
|
||||
exists(boolean eq | simple_comparison_eq(test, left, right, k, eq) |
|
||||
areEqual = true and testIsTrue = eq or areEqual = false and testIsTrue = eq.booleanNot()
|
||||
)
|
||||
// I think this is handled by forwarding in controlsBlock.
|
||||
/* or
|
||||
logical_comparison_eq(test, left, right, k, areEqual, testIsTrue) */
|
||||
or
|
||||
/* a == b + k => b == a - k */
|
||||
exists(int mk | k = -mk | compares_eq(test, right, left, mk, areEqual, testIsTrue))
|
||||
or
|
||||
complex_eq(test, left, right, k, areEqual, testIsTrue)
|
||||
or
|
||||
/* (x is true => (left == right + k)) => (!x is false => (left == right + k)) */
|
||||
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
|
||||
compares_eq(test.(LogicalNotInstruction).getOperand(), left, right, k, areEqual, isFalse)
|
||||
)
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left == right + k` form. */
|
||||
private predicate simple_comparison_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual) {
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareEQInstruction and right = cmp.getRightOperand() and k = 0 and areEqual = true
|
||||
or
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareNEInstruction and right = cmp.getRightOperand() and k = 0 and areEqual = false
|
||||
}
|
||||
|
||||
private predicate complex_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
sub_eq(cmp, left, right, k, areEqual, testIsTrue)
|
||||
or
|
||||
add_eq(cmp, left, right, k, areEqual, testIsTrue)
|
||||
}
|
||||
|
||||
|
||||
/* Simplification of inequality expressions
|
||||
* Simplify conditions in the source to the canonical form l < r + k.
|
||||
*/
|
||||
|
||||
/** Holds if `left < right + k` evaluates to `isLt` given that test is `testIsTrue`. */
|
||||
private predicate compares_lt(Instruction test, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
/* In the simple case, the test is the comparison, so isLt = testIsTrue */
|
||||
simple_comparison_lt(test, left, right, k) and isLt = true and testIsTrue = true
|
||||
or
|
||||
simple_comparison_lt(test, left, right, k) and isLt = false and testIsTrue = false
|
||||
or
|
||||
complex_lt(test, left, right, k, isLt, testIsTrue)
|
||||
or
|
||||
/* (not (left < right + k)) => (left >= right + k) */
|
||||
exists(boolean isGe | isLt = isGe.booleanNot() |
|
||||
compares_ge(test, left, right, k, isGe, testIsTrue)
|
||||
)
|
||||
or
|
||||
/* (x is true => (left < right + k)) => (!x is false => (left < right + k)) */
|
||||
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
|
||||
compares_lt(test.(LogicalNotInstruction).getOperand(), left, right, k, isLt, isFalse)
|
||||
)
|
||||
}
|
||||
|
||||
/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */
|
||||
private predicate compares_ge(Instruction test, Instruction left, Instruction right, int k, boolean isGe, boolean testIsTrue) {
|
||||
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, testIsTrue))
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left < right + k` form. */
|
||||
private predicate simple_comparison_lt(CompareInstruction cmp, Instruction left, Instruction right, int k) {
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareLTInstruction and right = cmp.getRightOperand() and k = 0
|
||||
or
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareLEInstruction and right = cmp.getRightOperand() and k = 1
|
||||
or
|
||||
right = cmp.getLeftOperand() and cmp instanceof CompareGTInstruction and left = cmp.getRightOperand() and k = 0
|
||||
or
|
||||
right = cmp.getLeftOperand() and cmp instanceof CompareGEInstruction and left = cmp.getRightOperand() and k = 1
|
||||
}
|
||||
|
||||
private predicate complex_lt(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
sub_lt(cmp, left, right, k, isLt, testIsTrue)
|
||||
or
|
||||
add_lt(cmp, left, right, k, isLt, testIsTrue)
|
||||
}
|
||||
|
||||
|
||||
/* left - x < right + c => left < right + (c+x)
|
||||
left < (right - x) + c => left < right + (c-x) */
|
||||
private predicate sub_lt(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
exists(SubInstruction lhs, int c, int x | compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
and k = c + x
|
||||
)
|
||||
or
|
||||
exists(SubInstruction rhs, int c, int x | compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
|
||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
and k = c - x
|
||||
)
|
||||
}
|
||||
|
||||
/* left + x < right + c => left < right + (c-x)
|
||||
left < (right + x) + c => left < right + (c+x) */
|
||||
private predicate add_lt(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
exists(AddInstruction lhs, int c, int x | compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
|
||||
(left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
or
|
||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
|
||||
)
|
||||
and k = c - x
|
||||
)
|
||||
or
|
||||
exists(AddInstruction rhs, int c, int x | compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
|
||||
(right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
or
|
||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
|
||||
)
|
||||
and k = c + x
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/* left - x == right + c => left == right + (c+x)
|
||||
left == (right - x) + c => left == right + (c-x) */
|
||||
private predicate sub_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
exists(SubInstruction lhs, int c, int x | compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
and k = c + x
|
||||
)
|
||||
or
|
||||
exists(SubInstruction rhs, int c, int x | compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
|
||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
and k = c - x
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/* left + x == right + c => left == right + (c-x)
|
||||
left == (right + x) + c => left == right + (c+x) */
|
||||
private predicate add_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
exists(AddInstruction lhs, int c, int x | compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
|
||||
(left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
or
|
||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
|
||||
)
|
||||
and k = c - x
|
||||
)
|
||||
or
|
||||
exists(AddInstruction rhs, int c, int x | compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
|
||||
(right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
or
|
||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
|
||||
)
|
||||
and k = c + x
|
||||
)
|
||||
}
|
||||
|
||||
/** The int value of integer constant expression. */
|
||||
private int int_value(Instruction i) {
|
||||
result = i.(IntegerConstantInstruction).getValue().toInt()
|
||||
}
|
||||
@@ -54,4 +54,10 @@ cached private module Cached {
|
||||
(usertypes(t,_,1) or usertypes(t,_,2) or usertypes(t,_,3) or usertypes(t,_,6)
|
||||
or usertypes(t,_,10) or usertypes(t,_,11) or usertypes(t,_,12))
|
||||
}
|
||||
|
||||
cached predicate isType(@type t) {
|
||||
not isClass(t)
|
||||
or
|
||||
t = resolveClass(_)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode {}
|
||||
|
||||
abstract class CompareOpcode extends BinaryOpcode {}
|
||||
|
||||
abstract class RelationalOpcode extends CompareOpcode {}
|
||||
|
||||
abstract class CopyOpcode extends Opcode {}
|
||||
|
||||
abstract class MemoryAccessOpcode extends Opcode {}
|
||||
@@ -117,10 +119,10 @@ module Opcode {
|
||||
class LogicalNot extends UnaryOpcode, TLogicalNot { override final string toString() { result = "LogicalNot" } }
|
||||
class CompareEQ extends CompareOpcode, TCompareEQ { override final string toString() { result = "CompareEQ" } }
|
||||
class CompareNE extends CompareOpcode, TCompareNE { override final string toString() { result = "CompareNE" } }
|
||||
class CompareLT extends CompareOpcode, TCompareLT { override final string toString() { result = "CompareLT" } }
|
||||
class CompareGT extends CompareOpcode, TCompareGT { override final string toString() { result = "CompareGT" } }
|
||||
class CompareLE extends CompareOpcode, TCompareLE { override final string toString() { result = "CompareLE" } }
|
||||
class CompareGE extends CompareOpcode, TCompareGE { override final string toString() { result = "CompareGE" } }
|
||||
class CompareLT extends RelationalOpcode, TCompareLT { override final string toString() { result = "CompareLT" } }
|
||||
class CompareGT extends RelationalOpcode, TCompareGT { override final string toString() { result = "CompareGT" } }
|
||||
class CompareLE extends RelationalOpcode, TCompareLE { override final string toString() { result = "CompareLE" } }
|
||||
class CompareGE extends RelationalOpcode, TCompareGE { override final string toString() { result = "CompareGE" } }
|
||||
class PointerAdd extends PointerOffsetOpcode, TPointerAdd { override final string toString() { result = "PointerAdd" } }
|
||||
class PointerSub extends PointerOffsetOpcode, TPointerSub { override final string toString() { result = "PointerSub" } }
|
||||
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { override final string toString() { result = "PointerDiff" } }
|
||||
|
||||
@@ -89,4 +89,12 @@ class IRBlock extends TIRBlock {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
final predicate isReachableFromFunctionEntry() {
|
||||
this = getFunctionIR().getEntryBlock() or
|
||||
getAPredecessor().isReachableFromFunctionEntry()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,16 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||
* would be printed by PrintIR.ql. For example:
|
||||
*
|
||||
* `mu0_28(int) = Store r0_26, r0_27`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
@@ -310,11 +320,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
* Gets the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
final Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -967,28 +985,110 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends CompareInstruction {
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
|
||||
*/
|
||||
Instruction getGreaterOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "lesser" (or "lesser-or-equal") side
|
||||
* of this relational instruction, that is, the side that is smaller
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
|
||||
*/
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGTInstruction extends CompareInstruction {
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLEInstruction extends CompareInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends CompareInstruction {
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
|
||||
@@ -197,8 +197,12 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getResultExpression()
|
||||
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
|
||||
@@ -89,4 +89,12 @@ class IRBlock extends TIRBlock {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
final predicate isReachableFromFunctionEntry() {
|
||||
this = getFunctionIR().getEntryBlock() or
|
||||
getAPredecessor().isReachableFromFunctionEntry()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,16 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||
* would be printed by PrintIR.ql. For example:
|
||||
*
|
||||
* `mu0_28(int) = Store r0_26, r0_27`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
@@ -310,11 +320,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
* Gets the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
final Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -967,28 +985,110 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends CompareInstruction {
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
|
||||
*/
|
||||
Instruction getGreaterOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "lesser" (or "lesser-or-equal") side
|
||||
* of this relational instruction, that is, the side that is smaller
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
|
||||
*/
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGTInstruction extends CompareInstruction {
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLEInstruction extends CompareInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends CompareInstruction {
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
|
||||
@@ -74,13 +74,25 @@ cached private module Cached {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
exists(TranslatedExpr translatedExpr |
|
||||
translatedExpr = getTranslatedExpr(result) and
|
||||
instruction = translatedExpr.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
exists(Expr converted, TranslatedExpr translatedExpr |
|
||||
result = converted.(Conversion).getExpr+()
|
||||
or
|
||||
result = converted
|
||||
|
|
||||
not result instanceof Conversion and
|
||||
translatedExpr = getTranslatedExpr(converted) and
|
||||
instruction = translatedExpr.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||
instruction.getTag(), tag)
|
||||
|
||||
@@ -89,4 +89,12 @@ class IRBlock extends TIRBlock {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
final predicate isReachableFromFunctionEntry() {
|
||||
this = getFunctionIR().getEntryBlock() or
|
||||
getAPredecessor().isReachableFromFunctionEntry()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,16 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||
* would be printed by PrintIR.ql. For example:
|
||||
*
|
||||
* `mu0_28(int) = Store r0_26, r0_27`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
@@ -310,11 +320,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
* Gets the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
final Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -967,28 +985,110 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends CompareInstruction {
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
|
||||
*/
|
||||
Instruction getGreaterOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "lesser" (or "lesser-or-equal") side
|
||||
* of this relational instruction, that is, the side that is smaller
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
|
||||
*/
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGTInstruction extends CompareInstruction {
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLEInstruction extends CompareInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends CompareInstruction {
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
|
||||
@@ -197,8 +197,12 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getResultExpression()
|
||||
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
|
||||
@@ -633,12 +633,26 @@ class PointsToExpr extends Expr
|
||||
pragma[noopt]
|
||||
Element pointsTo()
|
||||
{
|
||||
this.interesting() and exists(int set, @element thisEntity, @element resultEntity | thisEntity = underlyingElement(this) and pointstosets(set, thisEntity) and setlocations(set, resultEntity) and resultEntity = unresolveElement(result))
|
||||
this.interesting() and
|
||||
exists(int set, @element thisEntity, @element resultEntity |
|
||||
thisEntity = underlyingElement(this) and
|
||||
pointstosets(set, thisEntity) and
|
||||
setlocations(set, resultEntity) and
|
||||
resultEntity = localUnresolveElement(result)
|
||||
)
|
||||
}
|
||||
|
||||
float confidence() { result = 1.0 / count(this.pointsTo()) }
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used above in a `pragma[noopt]` context, which prevents its
|
||||
* customary inlining. We materialise it explicitly here.
|
||||
*/
|
||||
private @element localUnresolveElement(Element e) {
|
||||
result = unresolveElement(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if anything points to an element, that is, is equivalent to:
|
||||
* ```
|
||||
|
||||
@@ -13,6 +13,7 @@ predicate guardedAbs(Operation e, Expr use) {
|
||||
}
|
||||
|
||||
/** is the size of this use guarded to be less than something? */
|
||||
pragma[nomagic]
|
||||
predicate guardedLesser(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getLesserOperand().getAChild*() and
|
||||
@@ -33,6 +34,7 @@ predicate guardedLesser(Operation e, Expr use) {
|
||||
}
|
||||
|
||||
/** is the size of this use guarded to be greater than something? */
|
||||
pragma[nomagic]
|
||||
predicate guardedGreater(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getGreaterOperand().getAChild*() and
|
||||
|
||||
Reference in New Issue
Block a user