diff --git a/.gitignore b/.gitignore index 7e82b2f488ca..b5c88ce04abf 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,7 @@ # qltest projects and artifacts */ql/test/**/*.testproj */ql/test/**/*.actual -/.vs/slnx.sqlite -/.vs/ql/v15/Browse.VC.opendb -/.vs/ql/v15/Browse.VC.db -/.vs/ProjectSettings.json +# Visual studio temporaries, except a file used by QL4VS +.vs/* +!.vs/VSWorkspaceSettings.json diff --git a/change-notes/1.19/analysis-javascript.md b/change-notes/1.19/analysis-javascript.md index f68940ae6f77..47bf050789ba 100644 --- a/change-notes/1.19/analysis-javascript.md +++ b/change-notes/1.19/analysis-javascript.md @@ -4,6 +4,8 @@ * Modelling of taint flow through array operations has been improved. This may give additional results for the security queries. +* The taint tracking library now recognizes additional sanitization patterns. This may give fewer false-positive results for the security queries. + * Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following features: - file system access, for example through [fs-extra](https://github.com/jprichardson/node-fs-extra) or [globby](https://www.npmjs.com/package/globby) diff --git a/cpp/ql/src/semmle/code/cpp/XML.qll b/cpp/ql/src/semmle/code/cpp/XML.qll index b3f4cc420a0a..36a333da03b7 100644 --- a/cpp/ql/src/semmle/code/cpp/XML.qll +++ b/cpp/ql/src/semmle/code/cpp/XML.qll @@ -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() } } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll new file mode 100644 index 000000000000..55d5d4d8a84c --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -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() +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index dd12ea1a8a54..992dde33bcc7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -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" } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index c794c6cb288b..c51b05a073bb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -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() + } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index e63fd979def7..4603cf498481 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -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 getConvertedResultExpression() { + result = Construction::getInstructionConvertedResultExpression(this) + } + + /** + * Gets the unconverted `Expr` whose result is computed by this instruction, if any. */ - final Expr getResultExpression() { - result = Construction::getInstructionResultExpression(this) + 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 } + + override Instruction getLesserOperand() { + result = getRightOperand() + } + + override Instruction getGreaterOperand() { + result = getLeftOperand() + } + + override predicate isStrict() { + any() + } } -class CompareLEInstruction 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 CompareInstruction { +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 { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index f6e2034296d9..70af6ce64138 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -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) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index c794c6cb288b..c51b05a073bb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -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() + } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index e63fd979def7..4603cf498481 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -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 getConvertedResultExpression() { + result = Construction::getInstructionConvertedResultExpression(this) + } + + /** + * Gets the unconverted `Expr` whose result is computed by this instruction, if any. */ - final Expr getResultExpression() { - result = Construction::getInstructionResultExpression(this) + 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 } + + override Instruction getLesserOperand() { + result = getRightOperand() + } + + override Instruction getGreaterOperand() { + result = getLeftOperand() + } + + override predicate isStrict() { + any() + } } -class CompareLEInstruction 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 CompareInstruction { +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 { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 306180e764ec..d8c14c0f9508 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -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) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index c794c6cb288b..c51b05a073bb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -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() + } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index e63fd979def7..4603cf498481 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -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 getConvertedResultExpression() { + result = Construction::getInstructionConvertedResultExpression(this) + } + + /** + * Gets the unconverted `Expr` whose result is computed by this instruction, if any. */ - final Expr getResultExpression() { - result = Construction::getInstructionResultExpression(this) + 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 } + + override Instruction getLesserOperand() { + result = getRightOperand() + } + + override Instruction getGreaterOperand() { + result = getLeftOperand() + } + + override predicate isStrict() { + any() + } } -class CompareLEInstruction 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 CompareInstruction { +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 { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index f6e2034296d9..70af6ce64138 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -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) { diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/test.c b/cpp/ql/test/library-tests/controlflow/guards-ir/test.c new file mode 100644 index 000000000000..384d265440fb --- /dev/null +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/test.c @@ -0,0 +1,154 @@ + +int test(int x, int w, int z) { + int j; + long y = 50; + + // simple comparison + if (x > 0) { + y = 20; + z = 10; + } else { + y = 30; + } + + z = x + y; + + // More complex + if(x < 0 && y > 1) + y = 40; + else + y = 20; /* The && expression does not control this block as the x<0 expression jumps here if false. */ + + + z = 10; + + // while loop + while(x > 0) { + y = 10; + x--; + } + + z += y; + + // for loop + for(j = 0; j < 10; j++) { + y = 0; + w = 10; + } + + z += w; + + // nested control flow + for(j = 0; j < 10; j++) { + y = 30; + if(z > 0) + if(y > 0) { + w = 0; + break; + } else { + w = 20; + } + else { + w = 10; + continue; + } + x = 0; + } + + if (x == 0 || y < 0) { + y = 60; + z = 10; + } else + return z; + + z += x; + + return 0; +} + + +int test2(int x, int w, int z) { + int j; + long y = 50; + + // simple comparison + if (x == 0) { + y = 20; + z = 10; + } else { + y = 30; + } + + z = x + y; + + // More complex + if(x == 0 && y != 0) + y = 40; + else + y = 20; + + + z = 10; + + // while loop + while(x != 0) { + y = 10; + x--; + } + + z += y; + + // for loop + for(j = 0; j < 10; j++) { + y = 0; + w = 10; + } + + z += w; + + if (x == 0 || y < 0) { + y = 60; + z = 10; + } else + return z; + + z += x; + + return 0; +} + +int test3_condition(); +void test3_action(); + +void test3() { + int b = 0; + + if (1 && test3_condition()) { + b = 1; + test3_action(); + } + + if (b) { + test3_action(); + } +} + +void test4(int i) { + if (0) { + if (i) { + ; + } + } + return; +} + +void test5(int x) { + if (!x) { + test3(); + } +} + +void test6(int x, int y) { + return x && y; +} + diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/test.cpp b/cpp/ql/test/library-tests/controlflow/guards-ir/test.cpp new file mode 100644 index 000000000000..46d894813f9b --- /dev/null +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/test.cpp @@ -0,0 +1,54 @@ +class X +{ +public: + void set(); +}; + +class Y +{ +public: + Y* f(); + + const X* get() const { return 0; } + X* get() { return 0; } +}; + +Y* Y::f() +{ + if ( get() ) + get()->set(); + return 0; +} + +class Error { +public: + Error() {} +}; + +bool getABool(); + +void doSomething(int x) { + if (x == -1) { + throw new Error(); + } +} + +void doSomethingElse(int x); + +bool testWithCatch0(int v) +{ + try + { + if( getABool() ) + { + doSomething(v); + return true; + } + } + catch(Error &e) + { + doSomethingElse(v); + } + + return false; +} diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected new file mode 100644 index 000000000000..ef9603d1f0c0 --- /dev/null +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected @@ -0,0 +1,730 @@ +astGuards +| test.c:7:9:7:13 | ... > ... | +| test.c:17:8:17:12 | ... < ... | +| test.c:17:8:17:21 | ... && ... | +| test.c:17:17:17:21 | ... > ... | +| test.c:26:11:26:15 | ... > ... | +| test.c:34:16:34:21 | ... < ... | +| test.c:42:16:42:21 | ... < ... | +| test.c:44:12:44:16 | ... > ... | +| test.c:45:16:45:20 | ... > ... | +| test.c:58:9:58:14 | ... == ... | +| test.c:58:9:58:23 | ... \|\| ... | +| test.c:58:19:58:23 | ... < ... | +| test.c:75:9:75:14 | ... == ... | +| test.c:85:8:85:13 | ... == ... | +| test.c:85:8:85:23 | ... && ... | +| test.c:85:18:85:23 | ... != ... | +| test.c:94:11:94:16 | ... != ... | +| test.c:102:16:102:21 | ... < ... | +| test.c:109:9:109:14 | ... == ... | +| test.c:109:9:109:23 | ... \|\| ... | +| test.c:109:19:109:23 | ... < ... | +| test.c:126:7:126:7 | 1 | +| test.c:126:7:126:28 | ... && ... | +| test.c:126:12:126:26 | call to test3_condition | +| test.c:131:7:131:7 | b | +| test.c:137:7:137:7 | 0 | +| test.c:138:9:138:9 | i | +| test.c:146:7:146:8 | ! ... | +| test.c:146:8:146:8 | x | +| test.c:152:10:152:10 | x | +| test.c:152:10:152:15 | ... && ... | +| test.c:152:15:152:15 | y | +| test.cpp:18:8:18:10 | call to get | +| test.cpp:31:7:31:13 | ... == ... | +| test.cpp:42:13:42:20 | call to getABool | +astGuardsCompare +| 7 | 0 < x+0 when ... > ... is true | +| 7 | 0 >= x+0 when ... > ... is false | +| 7 | x < 0+1 when ... > ... is false | +| 7 | x >= 0+1 when ... > ... is true | +| 17 | 0 < x+1 when ... < ... is false | +| 17 | 0 >= x+1 when ... && ... is true | +| 17 | 0 >= x+1 when ... < ... is true | +| 17 | 1 < y+0 when ... && ... is true | +| 17 | 1 < y+0 when ... > ... is true | +| 17 | 1 >= y+0 when ... > ... is false | +| 17 | x < 0+0 when ... && ... is true | +| 17 | x < 0+0 when ... < ... is true | +| 17 | x >= 0+0 when ... < ... is false | +| 17 | y < 1+1 when ... > ... is false | +| 17 | y >= 1+1 when ... && ... is true | +| 17 | y >= 1+1 when ... > ... is true | +| 26 | 0 < x+0 when ... > ... is true | +| 26 | 0 >= x+0 when ... > ... is false | +| 26 | x < 0+1 when ... > ... is false | +| 26 | x >= 0+1 when ... > ... is true | +| 31 | - ... != x+0 when ... == ... is false | +| 31 | - ... == x+0 when ... == ... is true | +| 31 | x != - ...+0 when ... == ... is false | +| 31 | x == - ...+0 when ... == ... is true | +| 34 | 10 < j+1 when ... < ... is false | +| 34 | 10 >= j+1 when ... < ... is true | +| 34 | j < 10+0 when ... < ... is true | +| 34 | j >= 10+0 when ... < ... is false | +| 42 | 10 < j+1 when ... < ... is false | +| 42 | 10 >= j+1 when ... < ... is true | +| 42 | j < 10+0 when ... < ... is true | +| 42 | j >= 10+0 when ... < ... is false | +| 44 | 0 < z+0 when ... > ... is true | +| 44 | 0 >= z+0 when ... > ... is false | +| 44 | z < 0+1 when ... > ... is false | +| 44 | z >= 0+1 when ... > ... is true | +| 45 | 0 < y+0 when ... > ... is true | +| 45 | 0 >= y+0 when ... > ... is false | +| 45 | y < 0+1 when ... > ... is false | +| 45 | y >= 0+1 when ... > ... is true | +| 58 | 0 != x+0 when ... == ... is false | +| 58 | 0 != x+0 when ... \|\| ... is false | +| 58 | 0 < y+1 when ... < ... is false | +| 58 | 0 < y+1 when ... \|\| ... is false | +| 58 | 0 == x+0 when ... == ... is true | +| 58 | 0 >= y+1 when ... < ... is true | +| 58 | x != 0+0 when ... == ... is false | +| 58 | x != 0+0 when ... \|\| ... is false | +| 58 | x == 0+0 when ... == ... is true | +| 58 | y < 0+0 when ... < ... is true | +| 58 | y >= 0+0 when ... < ... is false | +| 58 | y >= 0+0 when ... \|\| ... is false | +| 75 | 0 != x+0 when ... == ... is false | +| 75 | 0 == x+0 when ... == ... is true | +| 75 | x != 0+0 when ... == ... is false | +| 75 | x == 0+0 when ... == ... is true | +| 85 | 0 != x+0 when ... == ... is false | +| 85 | 0 != y+0 when ... != ... is true | +| 85 | 0 != y+0 when ... && ... is true | +| 85 | 0 == x+0 when ... && ... is true | +| 85 | 0 == x+0 when ... == ... is true | +| 85 | 0 == y+0 when ... != ... is false | +| 85 | x != 0+0 when ... == ... is false | +| 85 | x == 0+0 when ... && ... is true | +| 85 | x == 0+0 when ... == ... is true | +| 85 | y != 0+0 when ... != ... is true | +| 85 | y != 0+0 when ... && ... is true | +| 85 | y == 0+0 when ... != ... is false | +| 94 | 0 != x+0 when ... != ... is true | +| 94 | 0 == x+0 when ... != ... is false | +| 94 | x != 0+0 when ... != ... is true | +| 94 | x == 0+0 when ... != ... is false | +| 102 | 10 < j+1 when ... < ... is false | +| 102 | 10 >= j+1 when ... < ... is true | +| 102 | j < 10+0 when ... < ... is true | +| 102 | j >= 10+0 when ... < ... is false | +| 109 | 0 != x+0 when ... == ... is false | +| 109 | 0 != x+0 when ... \|\| ... is false | +| 109 | 0 < y+1 when ... < ... is false | +| 109 | 0 < y+1 when ... \|\| ... is false | +| 109 | 0 == x+0 when ... == ... is true | +| 109 | 0 >= y+1 when ... < ... is true | +| 109 | x != 0+0 when ... == ... is false | +| 109 | x != 0+0 when ... \|\| ... is false | +| 109 | x == 0+0 when ... == ... is true | +| 109 | y < 0+0 when ... < ... is true | +| 109 | y >= 0+0 when ... < ... is false | +| 109 | y >= 0+0 when ... \|\| ... is false | +astGuardsControl +| test.c:7:9:7:13 | ... > ... | false | 10 | 11 | +| test.c:7:9:7:13 | ... > ... | true | 7 | 9 | +| test.c:17:8:17:12 | ... < ... | true | 17 | 17 | +| test.c:17:8:17:12 | ... < ... | true | 18 | 18 | +| test.c:17:8:17:21 | ... && ... | true | 18 | 18 | +| test.c:17:17:17:21 | ... > ... | true | 18 | 18 | +| test.c:26:11:26:15 | ... > ... | false | 2 | 2 | +| test.c:26:11:26:15 | ... > ... | false | 31 | 34 | +| test.c:26:11:26:15 | ... > ... | false | 34 | 34 | +| test.c:26:11:26:15 | ... > ... | false | 39 | 42 | +| test.c:26:11:26:15 | ... > ... | false | 42 | 42 | +| test.c:26:11:26:15 | ... > ... | false | 42 | 44 | +| test.c:26:11:26:15 | ... > ... | false | 45 | 45 | +| test.c:26:11:26:15 | ... > ... | false | 45 | 47 | +| test.c:26:11:26:15 | ... > ... | false | 48 | 55 | +| test.c:26:11:26:15 | ... > ... | false | 51 | 53 | +| test.c:26:11:26:15 | ... > ... | false | 56 | 58 | +| test.c:26:11:26:15 | ... > ... | false | 58 | 58 | +| test.c:26:11:26:15 | ... > ... | false | 58 | 66 | +| test.c:26:11:26:15 | ... > ... | false | 62 | 62 | +| test.c:26:11:26:15 | ... > ... | true | 26 | 28 | +| test.c:34:16:34:21 | ... < ... | false | 2 | 2 | +| test.c:34:16:34:21 | ... < ... | false | 39 | 42 | +| test.c:34:16:34:21 | ... < ... | false | 42 | 42 | +| test.c:34:16:34:21 | ... < ... | false | 42 | 44 | +| test.c:34:16:34:21 | ... < ... | false | 45 | 45 | +| test.c:34:16:34:21 | ... < ... | false | 45 | 47 | +| test.c:34:16:34:21 | ... < ... | false | 48 | 55 | +| test.c:34:16:34:21 | ... < ... | false | 51 | 53 | +| test.c:34:16:34:21 | ... < ... | false | 56 | 58 | +| test.c:34:16:34:21 | ... < ... | false | 58 | 58 | +| test.c:34:16:34:21 | ... < ... | false | 58 | 66 | +| test.c:34:16:34:21 | ... < ... | false | 62 | 62 | +| test.c:34:16:34:21 | ... < ... | true | 34 | 34 | +| test.c:42:16:42:21 | ... < ... | true | 42 | 42 | +| test.c:42:16:42:21 | ... < ... | true | 42 | 44 | +| test.c:42:16:42:21 | ... < ... | true | 45 | 45 | +| test.c:42:16:42:21 | ... < ... | true | 45 | 47 | +| test.c:42:16:42:21 | ... < ... | true | 48 | 55 | +| test.c:42:16:42:21 | ... < ... | true | 51 | 53 | +| test.c:44:12:44:16 | ... > ... | false | 51 | 53 | +| test.c:44:12:44:16 | ... > ... | true | 45 | 45 | +| test.c:44:12:44:16 | ... > ... | true | 45 | 47 | +| test.c:44:12:44:16 | ... > ... | true | 48 | 55 | +| test.c:45:16:45:20 | ... > ... | false | 48 | 55 | +| test.c:45:16:45:20 | ... > ... | true | 45 | 47 | +| test.c:58:9:58:14 | ... == ... | false | 58 | 58 | +| test.c:58:9:58:14 | ... == ... | false | 62 | 62 | +| test.c:58:9:58:23 | ... \|\| ... | false | 62 | 62 | +| test.c:58:19:58:23 | ... < ... | false | 62 | 62 | +| test.c:75:9:75:14 | ... == ... | false | 78 | 79 | +| test.c:75:9:75:14 | ... == ... | true | 75 | 77 | +| test.c:85:8:85:13 | ... == ... | true | 85 | 85 | +| test.c:85:8:85:13 | ... == ... | true | 86 | 86 | +| test.c:85:8:85:23 | ... && ... | true | 86 | 86 | +| test.c:85:18:85:23 | ... != ... | true | 86 | 86 | +| test.c:94:11:94:16 | ... != ... | false | 70 | 70 | +| test.c:94:11:94:16 | ... != ... | false | 99 | 102 | +| test.c:94:11:94:16 | ... != ... | false | 102 | 102 | +| test.c:94:11:94:16 | ... != ... | false | 107 | 109 | +| test.c:94:11:94:16 | ... != ... | false | 109 | 109 | +| test.c:94:11:94:16 | ... != ... | false | 109 | 117 | +| test.c:94:11:94:16 | ... != ... | false | 113 | 113 | +| test.c:94:11:94:16 | ... != ... | true | 94 | 96 | +| test.c:102:16:102:21 | ... < ... | false | 70 | 70 | +| test.c:102:16:102:21 | ... < ... | false | 107 | 109 | +| test.c:102:16:102:21 | ... < ... | false | 109 | 109 | +| test.c:102:16:102:21 | ... < ... | false | 109 | 117 | +| test.c:102:16:102:21 | ... < ... | false | 113 | 113 | +| test.c:102:16:102:21 | ... < ... | true | 102 | 102 | +| test.c:109:9:109:14 | ... == ... | false | 109 | 109 | +| test.c:109:9:109:14 | ... == ... | false | 113 | 113 | +| test.c:109:9:109:23 | ... \|\| ... | false | 113 | 113 | +| test.c:109:19:109:23 | ... < ... | false | 113 | 113 | +| test.c:126:7:126:7 | 1 | true | 126 | 126 | +| test.c:126:7:126:7 | 1 | true | 126 | 128 | +| test.c:126:7:126:28 | ... && ... | true | 126 | 128 | +| test.c:126:12:126:26 | call to test3_condition | true | 126 | 128 | +| test.c:131:7:131:7 | b | true | 131 | 132 | +| test.c:137:7:137:7 | 0 | true | 137 | 138 | +| test.c:137:7:137:7 | 0 | true | 138 | 139 | +| test.c:138:9:138:9 | i | true | 138 | 139 | +| test.c:146:7:146:8 | ! ... | true | 146 | 147 | +| test.c:146:8:146:8 | x | false | 146 | 147 | +| test.c:152:10:152:10 | x | true | 151 | 152 | +| test.c:152:10:152:10 | x | true | 152 | 152 | +| test.c:152:10:152:15 | ... && ... | true | 151 | 152 | +| test.c:152:15:152:15 | y | true | 151 | 152 | +| test.cpp:18:8:18:10 | call to get | true | 19 | 19 | +| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 | +| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 | +| test.cpp:31:7:31:13 | ... == ... | true | 30 | 30 | +| test.cpp:31:7:31:13 | ... == ... | true | 31 | 32 | +| test.cpp:42:13:42:20 | call to getABool | false | 53 | 53 | +| test.cpp:42:13:42:20 | call to getABool | true | 43 | 45 | +astGuardsEnsure +| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | test.c:7:13:7:13 | 0 | 1 | 10 | 11 | +| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | test.c:7:13:7:13 | 0 | 1 | 7 | 9 | +| test.c:7:9:7:13 | ... > ... | test.c:7:13:7:13 | 0 | < | test.c:7:9:7:9 | x | 0 | 7 | 9 | +| test.c:7:9:7:13 | ... > ... | test.c:7:13:7:13 | 0 | >= | test.c:7:9:7:9 | x | 0 | 10 | 11 | +| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | test.c:17:12:17:12 | 0 | 0 | 17 | 17 | +| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | test.c:17:12:17:12 | 0 | 0 | 18 | 18 | +| test.c:17:8:17:12 | ... < ... | test.c:17:12:17:12 | 0 | >= | test.c:17:8:17:8 | x | 1 | 17 | 17 | +| test.c:17:8:17:12 | ... < ... | test.c:17:12:17:12 | 0 | >= | test.c:17:8:17:8 | x | 1 | 18 | 18 | +| test.c:17:8:17:21 | ... && ... | test.c:17:8:17:8 | x | < | test.c:17:12:17:12 | 0 | 0 | 18 | 18 | +| test.c:17:8:17:21 | ... && ... | test.c:17:12:17:12 | 0 | >= | test.c:17:8:17:8 | x | 1 | 18 | 18 | +| test.c:17:8:17:21 | ... && ... | test.c:17:17:17:17 | y | >= | test.c:17:21:17:21 | 1 | 1 | 18 | 18 | +| test.c:17:8:17:21 | ... && ... | test.c:17:21:17:21 | 1 | < | test.c:17:17:17:17 | y | 0 | 18 | 18 | +| test.c:17:17:17:21 | ... > ... | test.c:17:17:17:17 | y | >= | test.c:17:21:17:21 | 1 | 1 | 18 | 18 | +| test.c:17:17:17:21 | ... > ... | test.c:17:21:17:21 | 1 | < | test.c:17:17:17:17 | y | 0 | 18 | 18 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 2 | 2 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 31 | 34 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 34 | 34 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 39 | 42 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 42 | 42 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 42 | 44 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 45 | 45 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 45 | 47 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 48 | 55 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 51 | 53 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 56 | 58 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 58 | 58 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 58 | 66 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 62 | 62 | +| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | >= | test.c:26:15:26:15 | 0 | 1 | 26 | 28 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | < | test.c:26:11:26:11 | x | 0 | 26 | 28 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 2 | 2 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 31 | 34 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 34 | 34 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 39 | 42 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 42 | 42 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 42 | 44 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 45 | 45 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 45 | 47 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 48 | 55 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 51 | 53 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 56 | 58 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 58 | 58 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 58 | 66 | +| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 62 | 62 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | < | test.c:34:20:34:21 | 10 | 0 | 34 | 34 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 2 | 2 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 39 | 42 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 42 | 42 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 42 | 44 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 45 | 45 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 45 | 47 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 48 | 55 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 51 | 53 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 56 | 58 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 58 | 58 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 58 | 66 | +| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 62 | 62 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 2 | 2 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 39 | 42 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 42 | 42 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 42 | 44 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 45 | 45 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 45 | 47 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 48 | 55 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 51 | 53 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 56 | 58 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 58 | 58 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 58 | 66 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 62 | 62 | +| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | >= | test.c:34:16:34:16 | j | 1 | 34 | 34 | +| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 42 | 42 | +| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 42 | 44 | +| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 45 | 45 | +| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 45 | 47 | +| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 48 | 55 | +| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 51 | 53 | +| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 42 | 42 | +| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 42 | 44 | +| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 45 | 45 | +| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 45 | 47 | +| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 48 | 55 | +| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 51 | 53 | +| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | test.c:44:16:44:16 | 0 | 1 | 51 | 53 | +| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 45 | +| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 47 | +| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 48 | 55 | +| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 45 | +| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 47 | +| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 48 | 55 | +| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | >= | test.c:44:12:44:12 | z | 0 | 51 | 53 | +| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | < | test.c:45:20:45:20 | 0 | 1 | 48 | 55 | +| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | >= | test.c:45:20:45:20 | 0 | 1 | 45 | 47 | +| test.c:45:16:45:20 | ... > ... | test.c:45:20:45:20 | 0 | < | test.c:45:16:45:16 | y | 0 | 45 | 47 | +| test.c:45:16:45:20 | ... > ... | test.c:45:20:45:20 | 0 | >= | test.c:45:16:45:16 | y | 0 | 48 | 55 | +| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | test.c:58:14:58:14 | 0 | 0 | 58 | 58 | +| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | test.c:58:14:58:14 | 0 | 0 | 62 | 62 | +| test.c:58:9:58:14 | ... == ... | test.c:58:14:58:14 | 0 | != | test.c:58:9:58:9 | x | 0 | 58 | 58 | +| test.c:58:9:58:14 | ... == ... | test.c:58:14:58:14 | 0 | != | test.c:58:9:58:9 | x | 0 | 62 | 62 | +| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:9 | x | != | test.c:58:14:58:14 | 0 | 0 | 62 | 62 | +| test.c:58:9:58:23 | ... \|\| ... | test.c:58:14:58:14 | 0 | != | test.c:58:9:58:9 | x | 0 | 62 | 62 | +| test.c:58:9:58:23 | ... \|\| ... | test.c:58:19:58:19 | y | >= | test.c:58:23:58:23 | 0 | 0 | 62 | 62 | +| test.c:58:9:58:23 | ... \|\| ... | test.c:58:23:58:23 | 0 | < | test.c:58:19:58:19 | y | 1 | 62 | 62 | +| test.c:58:19:58:23 | ... < ... | test.c:58:19:58:19 | y | >= | test.c:58:23:58:23 | 0 | 0 | 62 | 62 | +| test.c:58:19:58:23 | ... < ... | test.c:58:23:58:23 | 0 | < | test.c:58:19:58:19 | y | 1 | 62 | 62 | +| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | != | test.c:75:14:75:14 | 0 | 0 | 78 | 79 | +| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 75 | 77 | +| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | != | test.c:75:9:75:9 | x | 0 | 78 | 79 | +| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 75 | 77 | +| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 85 | 85 | +| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 | +| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 85 | 85 | +| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 | +| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 | +| test.c:85:8:85:23 | ... && ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 | +| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | test.c:85:23:85:23 | 0 | 0 | 86 | 86 | +| test.c:85:8:85:23 | ... && ... | test.c:85:23:85:23 | 0 | != | test.c:85:18:85:18 | y | 0 | 86 | 86 | +| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:18 | y | != | test.c:85:23:85:23 | 0 | 0 | 86 | 86 | +| test.c:85:18:85:23 | ... != ... | test.c:85:23:85:23 | 0 | != | test.c:85:18:85:18 | y | 0 | 86 | 86 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | != | test.c:94:16:94:16 | 0 | 0 | 94 | 96 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 70 | 70 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 99 | 102 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 102 | 102 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 107 | 109 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 109 | 109 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 109 | 117 | +| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 113 | 113 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | != | test.c:94:11:94:11 | x | 0 | 94 | 96 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 70 | 70 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 99 | 102 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 102 | 102 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 107 | 109 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 109 | 109 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 109 | 117 | +| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 113 | 113 | +| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | < | test.c:102:20:102:21 | 10 | 0 | 102 | 102 | +| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 70 | 70 | +| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 107 | 109 | +| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 109 | 109 | +| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 109 | 117 | +| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 113 | 113 | +| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 70 | 70 | +| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 107 | 109 | +| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 109 | 109 | +| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 109 | 117 | +| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 113 | 113 | +| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | >= | test.c:102:16:102:16 | j | 1 | 102 | 102 | +| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | test.c:109:14:109:14 | 0 | 0 | 109 | 109 | +| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | test.c:109:14:109:14 | 0 | 0 | 113 | 113 | +| test.c:109:9:109:14 | ... == ... | test.c:109:14:109:14 | 0 | != | test.c:109:9:109:9 | x | 0 | 109 | 109 | +| test.c:109:9:109:14 | ... == ... | test.c:109:14:109:14 | 0 | != | test.c:109:9:109:9 | x | 0 | 113 | 113 | +| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | test.c:109:14:109:14 | 0 | 0 | 113 | 113 | +| test.c:109:9:109:23 | ... \|\| ... | test.c:109:14:109:14 | 0 | != | test.c:109:9:109:9 | x | 0 | 113 | 113 | +| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | test.c:109:23:109:23 | 0 | 0 | 113 | 113 | +| test.c:109:9:109:23 | ... \|\| ... | test.c:109:23:109:23 | 0 | < | test.c:109:19:109:19 | y | 1 | 113 | 113 | +| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | test.c:109:23:109:23 | 0 | 0 | 113 | 113 | +| test.c:109:19:109:23 | ... < ... | test.c:109:23:109:23 | 0 | < | test.c:109:19:109:19 | y | 1 | 113 | 113 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | test.cpp:31:12:31:13 | - ... | 0 | 30 | 30 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | test.cpp:31:12:31:13 | - ... | 0 | 34 | 34 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | test.cpp:31:12:31:13 | - ... | 0 | 30 | 30 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | test.cpp:31:12:31:13 | - ... | 0 | 31 | 32 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | != | test.cpp:31:7:31:7 | x | 0 | 30 | 30 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | != | test.cpp:31:7:31:7 | x | 0 | 34 | 34 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 30 | 30 | +| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 31 | 32 | +irGuards +| test.c:7:9:7:13 | CompareGT: ... > ... | +| test.c:17:8:17:12 | CompareLT: ... < ... | +| test.c:17:17:17:21 | CompareGT: ... > ... | +| test.c:26:11:26:15 | CompareGT: ... > ... | +| test.c:34:16:34:21 | CompareLT: ... < ... | +| test.c:42:16:42:21 | CompareLT: ... < ... | +| test.c:44:12:44:16 | CompareGT: ... > ... | +| test.c:45:16:45:20 | CompareGT: ... > ... | +| test.c:58:9:58:14 | CompareEQ: ... == ... | +| test.c:58:19:58:23 | CompareLT: ... < ... | +| test.c:75:9:75:14 | CompareEQ: ... == ... | +| test.c:85:8:85:13 | CompareEQ: ... == ... | +| test.c:85:18:85:23 | CompareNE: ... != ... | +| test.c:94:11:94:16 | CompareNE: ... != ... | +| test.c:102:16:102:21 | CompareLT: ... < ... | +| test.c:109:9:109:14 | CompareEQ: ... == ... | +| test.c:109:19:109:23 | CompareLT: ... < ... | +| test.c:126:7:126:7 | Constant: 1 | +| test.c:126:12:126:26 | Call: call to test3_condition | +| test.c:131:7:131:7 | Load: b | +| test.c:137:7:137:7 | Constant: 0 | +| test.c:138:9:138:9 | Load: i | +| test.c:146:8:146:8 | Load: x | +| test.c:152:10:152:10 | Load: x | +| test.c:152:15:152:15 | Load: y | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | +| test.cpp:42:13:42:20 | Call: call to getABool | +irGuardsCompare +| 7 | 0 < x+0 when CompareGT: ... > ... is true | +| 7 | 0 >= x+0 when CompareGT: ... > ... is false | +| 7 | x < 0+1 when CompareGT: ... > ... is false | +| 7 | x >= 0+1 when CompareGT: ... > ... is true | +| 17 | 0 < x+1 when CompareLT: ... < ... is false | +| 17 | 0 >= x+1 when CompareLT: ... < ... is true | +| 17 | 1 < y+0 when CompareGT: ... > ... is true | +| 17 | 1 >= y+0 when CompareGT: ... > ... is false | +| 17 | x < 0+0 when CompareLT: ... < ... is true | +| 17 | x >= 0+0 when CompareLT: ... < ... is false | +| 17 | y < 1+1 when CompareGT: ... > ... is false | +| 17 | y >= 1+1 when CompareGT: ... > ... is true | +| 26 | 0 < x+0 when CompareGT: ... > ... is true | +| 26 | 0 >= x+0 when CompareGT: ... > ... is false | +| 26 | x < 0+1 when CompareGT: ... > ... is false | +| 26 | x >= 0+1 when CompareGT: ... > ... is true | +| 31 | - ... != x+0 when CompareEQ: ... == ... is false | +| 31 | - ... == x+0 when CompareEQ: ... == ... is true | +| 31 | x != - ...+0 when CompareEQ: ... == ... is false | +| 31 | x == - ...+0 when CompareEQ: ... == ... is true | +| 34 | 10 < j+1 when CompareLT: ... < ... is false | +| 34 | 10 >= j+1 when CompareLT: ... < ... is true | +| 34 | j < 10+0 when CompareLT: ... < ... is true | +| 34 | j >= 10+0 when CompareLT: ... < ... is false | +| 42 | 10 < j+1 when CompareLT: ... < ... is false | +| 42 | 10 >= j+1 when CompareLT: ... < ... is true | +| 42 | j < 10+0 when CompareLT: ... < ... is true | +| 42 | j >= 10+0 when CompareLT: ... < ... is false | +| 44 | 0 < z+0 when CompareGT: ... > ... is true | +| 44 | 0 >= z+0 when CompareGT: ... > ... is false | +| 44 | z < 0+1 when CompareGT: ... > ... is false | +| 44 | z >= 0+1 when CompareGT: ... > ... is true | +| 45 | 0 < y+0 when CompareGT: ... > ... is true | +| 45 | 0 >= y+0 when CompareGT: ... > ... is false | +| 45 | y < 0+1 when CompareGT: ... > ... is false | +| 45 | y >= 0+1 when CompareGT: ... > ... is true | +| 58 | 0 != x+0 when CompareEQ: ... == ... is false | +| 58 | 0 < y+1 when CompareLT: ... < ... is false | +| 58 | 0 == x+0 when CompareEQ: ... == ... is true | +| 58 | 0 >= y+1 when CompareLT: ... < ... is true | +| 58 | x != 0+0 when CompareEQ: ... == ... is false | +| 58 | x == 0+0 when CompareEQ: ... == ... is true | +| 58 | y < 0+0 when CompareLT: ... < ... is true | +| 58 | y >= 0+0 when CompareLT: ... < ... is false | +| 75 | 0 != x+0 when CompareEQ: ... == ... is false | +| 75 | 0 == x+0 when CompareEQ: ... == ... is true | +| 75 | x != 0+0 when CompareEQ: ... == ... is false | +| 75 | x == 0+0 when CompareEQ: ... == ... is true | +| 85 | 0 != x+0 when CompareEQ: ... == ... is false | +| 85 | 0 != y+0 when CompareNE: ... != ... is true | +| 85 | 0 == x+0 when CompareEQ: ... == ... is true | +| 85 | 0 == y+0 when CompareNE: ... != ... is false | +| 85 | x != 0+0 when CompareEQ: ... == ... is false | +| 85 | x == 0+0 when CompareEQ: ... == ... is true | +| 85 | y != 0+0 when CompareNE: ... != ... is true | +| 85 | y == 0+0 when CompareNE: ... != ... is false | +| 94 | 0 != x+0 when CompareNE: ... != ... is true | +| 94 | 0 == x+0 when CompareNE: ... != ... is false | +| 94 | x != 0+0 when CompareNE: ... != ... is true | +| 94 | x == 0+0 when CompareNE: ... != ... is false | +| 102 | 10 < j+1 when CompareLT: ... < ... is false | +| 102 | 10 >= j+1 when CompareLT: ... < ... is true | +| 102 | j < 10+0 when CompareLT: ... < ... is true | +| 102 | j >= 10+0 when CompareLT: ... < ... is false | +| 109 | 0 != x+0 when CompareEQ: ... == ... is false | +| 109 | 0 < y+1 when CompareLT: ... < ... is false | +| 109 | 0 == x+0 when CompareEQ: ... == ... is true | +| 109 | 0 >= y+1 when CompareLT: ... < ... is true | +| 109 | x != 0+0 when CompareEQ: ... == ... is false | +| 109 | x == 0+0 when CompareEQ: ... == ... is true | +| 109 | y < 0+0 when CompareLT: ... < ... is true | +| 109 | y >= 0+0 when CompareLT: ... < ... is false | +irGuardsControl +| test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 | +| test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 | +| test.c:17:8:17:12 | CompareLT: ... < ... | true | 17 | 17 | +| test.c:17:8:17:12 | CompareLT: ... < ... | true | 18 | 18 | +| test.c:17:17:17:21 | CompareGT: ... > ... | true | 18 | 18 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 2 | 2 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 31 | 31 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 34 | 34 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 35 | 35 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 39 | 39 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 42 | 42 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 43 | 43 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 45 | 45 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 46 | 46 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 49 | 49 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 52 | 52 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 56 | 56 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 58 | 58 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 59 | 59 | +| test.c:26:11:26:15 | CompareGT: ... > ... | false | 62 | 62 | +| test.c:26:11:26:15 | CompareGT: ... > ... | true | 27 | 27 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 2 | 2 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 39 | 39 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 42 | 42 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 43 | 43 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 45 | 45 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 46 | 46 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 49 | 49 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 52 | 52 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 56 | 56 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 58 | 58 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 59 | 59 | +| test.c:34:16:34:21 | CompareLT: ... < ... | false | 62 | 62 | +| test.c:34:16:34:21 | CompareLT: ... < ... | true | 35 | 35 | +| test.c:42:16:42:21 | CompareLT: ... < ... | true | 42 | 42 | +| test.c:42:16:42:21 | CompareLT: ... < ... | true | 43 | 43 | +| test.c:42:16:42:21 | CompareLT: ... < ... | true | 45 | 45 | +| test.c:42:16:42:21 | CompareLT: ... < ... | true | 46 | 46 | +| test.c:42:16:42:21 | CompareLT: ... < ... | true | 49 | 49 | +| test.c:42:16:42:21 | CompareLT: ... < ... | true | 52 | 52 | +| test.c:44:12:44:16 | CompareGT: ... > ... | false | 52 | 52 | +| test.c:44:12:44:16 | CompareGT: ... > ... | true | 45 | 45 | +| test.c:44:12:44:16 | CompareGT: ... > ... | true | 46 | 46 | +| test.c:44:12:44:16 | CompareGT: ... > ... | true | 49 | 49 | +| test.c:45:16:45:20 | CompareGT: ... > ... | false | 49 | 49 | +| test.c:45:16:45:20 | CompareGT: ... > ... | true | 46 | 46 | +| test.c:58:9:58:14 | CompareEQ: ... == ... | false | 58 | 58 | +| test.c:58:9:58:14 | CompareEQ: ... == ... | false | 62 | 62 | +| test.c:58:19:58:23 | CompareLT: ... < ... | false | 62 | 62 | +| test.c:75:9:75:14 | CompareEQ: ... == ... | false | 79 | 79 | +| test.c:75:9:75:14 | CompareEQ: ... == ... | true | 76 | 76 | +| test.c:85:8:85:13 | CompareEQ: ... == ... | true | 85 | 85 | +| test.c:85:8:85:13 | CompareEQ: ... == ... | true | 86 | 86 | +| test.c:85:18:85:23 | CompareNE: ... != ... | true | 86 | 86 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 70 | 70 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 99 | 99 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 102 | 102 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 103 | 103 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 107 | 107 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 109 | 109 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 110 | 110 | +| test.c:94:11:94:16 | CompareNE: ... != ... | false | 113 | 113 | +| test.c:94:11:94:16 | CompareNE: ... != ... | true | 95 | 95 | +| test.c:102:16:102:21 | CompareLT: ... < ... | false | 70 | 70 | +| test.c:102:16:102:21 | CompareLT: ... < ... | false | 107 | 107 | +| test.c:102:16:102:21 | CompareLT: ... < ... | false | 109 | 109 | +| test.c:102:16:102:21 | CompareLT: ... < ... | false | 110 | 110 | +| test.c:102:16:102:21 | CompareLT: ... < ... | false | 113 | 113 | +| test.c:102:16:102:21 | CompareLT: ... < ... | true | 103 | 103 | +| test.c:109:9:109:14 | CompareEQ: ... == ... | false | 109 | 109 | +| test.c:109:9:109:14 | CompareEQ: ... == ... | false | 113 | 113 | +| test.c:109:19:109:23 | CompareLT: ... < ... | false | 113 | 113 | +| test.c:126:7:126:7 | Constant: 1 | true | 126 | 126 | +| test.c:126:7:126:7 | Constant: 1 | true | 127 | 127 | +| test.c:126:12:126:26 | Call: call to test3_condition | true | 127 | 127 | +| test.c:131:7:131:7 | Load: b | true | 132 | 132 | +| test.c:137:7:137:7 | Constant: 0 | true | 138 | 138 | +| test.c:137:7:137:7 | Constant: 0 | true | 139 | 139 | +| test.c:138:9:138:9 | Load: i | true | 139 | 139 | +| test.c:146:8:146:8 | Load: x | false | 147 | 147 | +| test.c:152:10:152:10 | Load: x | true | 152 | 152 | +| test.c:152:15:152:15 | Load: y | true | 152 | 152 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | true | 0 | 0 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | false | 34 | 34 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 30 | 30 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 32 | 32 | +| test.cpp:42:13:42:20 | Call: call to getABool | false | 53 | 53 | +| test.cpp:42:13:42:20 | Call: call to getABool | true | 44 | 44 | +irGuardsEnsure +| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:9 | Load: x | < | test.c:7:13:7:13 | Constant: 0 | 1 | 11 | 11 | +| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:9 | Load: x | >= | test.c:7:13:7:13 | Constant: 0 | 1 | 8 | 8 | +| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:13:7:13 | Constant: 0 | < | test.c:7:9:7:9 | Load: x | 0 | 8 | 8 | +| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:13:7:13 | Constant: 0 | >= | test.c:7:9:7:9 | Load: x | 0 | 11 | 11 | +| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:8 | Load: x | < | test.c:17:12:17:12 | Constant: 0 | 0 | 17 | 17 | +| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:8 | Load: x | < | test.c:17:12:17:12 | Constant: 0 | 0 | 18 | 18 | +| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:12:17:12 | Constant: 0 | >= | test.c:17:8:17:8 | Load: x | 1 | 17 | 17 | +| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:12:17:12 | Constant: 0 | >= | test.c:17:8:17:8 | Load: x | 1 | 18 | 18 | +| test.c:17:17:17:21 | CompareGT: ... > ... | test.c:17:17:17:17 | Load: y | >= | test.c:17:21:17:21 | Constant: (long)... | 1 | 18 | 18 | +| test.c:17:17:17:21 | CompareGT: ... > ... | test.c:17:21:17:21 | Constant: (long)... | < | test.c:17:17:17:17 | Load: y | 0 | 18 | 18 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 2 | 2 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 31 | 31 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 34 | 34 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 35 | 35 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 39 | 39 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 42 | 42 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 43 | 43 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 45 | 45 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 46 | 46 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 49 | 49 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 52 | 52 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 56 | 56 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 58 | 58 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 59 | 59 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 62 | 62 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | >= | test.c:26:15:26:15 | Constant: 0 | 1 | 27 | 27 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | < | test.c:26:11:26:11 | Load: x | 0 | 27 | 27 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 2 | 2 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 31 | 31 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 34 | 34 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 35 | 35 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 39 | 39 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 42 | 42 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 43 | 43 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 45 | 45 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 46 | 46 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 49 | 49 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 52 | 52 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 56 | 56 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 58 | 58 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 59 | 59 | +| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 62 | 62 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | < | test.c:34:20:34:21 | Constant: 10 | 0 | 35 | 35 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 2 | 2 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 39 | 39 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 42 | 42 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 43 | 43 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 45 | 45 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 46 | 46 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 49 | 49 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 52 | 52 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 56 | 56 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 58 | 58 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 59 | 59 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 62 | 62 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 2 | 2 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 39 | 39 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 42 | 42 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 43 | 43 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 45 | 45 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 46 | 46 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 49 | 49 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 52 | 52 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 56 | 56 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 58 | 58 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 59 | 59 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 62 | 62 | +| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | >= | test.c:34:16:34:16 | Load: j | 1 | 35 | 35 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 42 | 42 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 43 | 43 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 45 | 45 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 46 | 46 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 49 | 49 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 52 | 52 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 42 | 42 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 43 | 43 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 45 | 45 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 46 | 46 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 49 | 49 | +| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 52 | 52 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | < | test.c:44:16:44:16 | Constant: 0 | 1 | 52 | 52 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | test.c:44:16:44:16 | Constant: 0 | 1 | 45 | 45 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | test.c:44:16:44:16 | Constant: 0 | 1 | 46 | 46 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | test.c:44:16:44:16 | Constant: 0 | 1 | 49 | 49 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | < | test.c:44:12:44:12 | Load: z | 0 | 45 | 45 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | < | test.c:44:12:44:12 | Load: z | 0 | 46 | 46 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | < | test.c:44:12:44:12 | Load: z | 0 | 49 | 49 | +| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | >= | test.c:44:12:44:12 | Load: z | 0 | 52 | 52 | +| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:16:45:16 | Load: y | < | test.c:45:20:45:20 | Constant: (long)... | 1 | 49 | 49 | +| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:16:45:16 | Load: y | >= | test.c:45:20:45:20 | Constant: (long)... | 1 | 46 | 46 | +| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:20:45:20 | Constant: (long)... | < | test.c:45:16:45:16 | Load: y | 0 | 46 | 46 | +| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:20:45:20 | Constant: (long)... | >= | test.c:45:16:45:16 | Load: y | 0 | 49 | 49 | +| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:9 | Load: x | != | test.c:58:14:58:14 | Constant: 0 | 0 | 58 | 58 | +| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:9 | Load: x | != | test.c:58:14:58:14 | Constant: 0 | 0 | 62 | 62 | +| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:14:58:14 | Constant: 0 | != | test.c:58:9:58:9 | Load: x | 0 | 58 | 58 | +| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:14:58:14 | Constant: 0 | != | test.c:58:9:58:9 | Load: x | 0 | 62 | 62 | +| test.c:58:19:58:23 | CompareLT: ... < ... | test.c:58:19:58:19 | Load: y | >= | test.c:58:23:58:23 | Constant: (long)... | 0 | 62 | 62 | +| test.c:58:19:58:23 | CompareLT: ... < ... | test.c:58:23:58:23 | Constant: (long)... | < | test.c:58:19:58:19 | Load: y | 1 | 62 | 62 | +| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | != | test.c:75:14:75:14 | Constant: 0 | 0 | 79 | 79 | +| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | test.c:75:14:75:14 | Constant: 0 | 0 | 76 | 76 | +| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | != | test.c:75:9:75:9 | Load: x | 0 | 79 | 79 | +| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | == | test.c:75:9:75:9 | Load: x | 0 | 76 | 76 | +| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | test.c:85:13:85:13 | Constant: 0 | 0 | 85 | 85 | +| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | test.c:85:13:85:13 | Constant: 0 | 0 | 86 | 86 | +| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:13:85:13 | Constant: 0 | == | test.c:85:8:85:8 | Load: x | 0 | 85 | 85 | +| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:13:85:13 | Constant: 0 | == | test.c:85:8:85:8 | Load: x | 0 | 86 | 86 | +| test.c:85:18:85:23 | CompareNE: ... != ... | test.c:85:18:85:18 | Load: y | != | test.c:85:23:85:23 | Constant: (long)... | 0 | 86 | 86 | +| test.c:85:18:85:23 | CompareNE: ... != ... | test.c:85:23:85:23 | Constant: (long)... | != | test.c:85:18:85:18 | Load: y | 0 | 86 | 86 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | != | test.c:94:16:94:16 | Constant: 0 | 0 | 95 | 95 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 70 | 70 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 99 | 99 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 102 | 102 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 103 | 103 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 107 | 107 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 109 | 109 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 110 | 110 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 113 | 113 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | != | test.c:94:11:94:11 | Load: x | 0 | 95 | 95 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 70 | 70 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 99 | 99 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 102 | 102 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 103 | 103 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 107 | 107 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 109 | 109 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 110 | 110 | +| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 113 | 113 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | < | test.c:102:20:102:21 | Constant: 10 | 0 | 103 | 103 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 70 | 70 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 107 | 107 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 109 | 109 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 110 | 110 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 113 | 113 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 70 | 70 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 107 | 107 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 109 | 109 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 110 | 110 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 113 | 113 | +| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | >= | test.c:102:16:102:16 | Load: j | 1 | 103 | 103 | +| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | test.c:109:14:109:14 | Constant: 0 | 0 | 109 | 109 | +| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | test.c:109:14:109:14 | Constant: 0 | 0 | 113 | 113 | +| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:14:109:14 | Constant: 0 | != | test.c:109:9:109:9 | Load: x | 0 | 109 | 109 | +| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:14:109:14 | Constant: 0 | != | test.c:109:9:109:9 | Load: x | 0 | 113 | 113 | +| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | test.c:109:23:109:23 | Constant: (long)... | 0 | 113 | 113 | +| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:23:109:23 | Constant: (long)... | < | test.c:109:19:109:19 | Load: y | 1 | 113 | 113 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | test.cpp:18:8:18:12 | Constant: (bool)... | 0 | 0 | 0 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | Constant: (bool)... | != | test.cpp:18:8:18:10 | Call: call to get | 0 | 0 | 0 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | test.cpp:31:12:31:13 | Constant: - ... | 0 | 34 | 34 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 30 | 30 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 32 | 32 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:12:31:13 | Constant: - ... | != | test.cpp:31:7:31:7 | Load: x | 0 | 34 | 34 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:12:31:13 | Constant: - ... | == | test.cpp:31:7:31:7 | Load: x | 0 | 30 | 30 | +| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:12:31:13 | Constant: - ... | == | test.cpp:31:7:31:7 | Load: x | 0 | 32 | 32 | diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.ql b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.ql new file mode 100644 index 000000000000..2bb8b2f9fa99 --- /dev/null +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.ql @@ -0,0 +1,91 @@ +import cpp +import semmle.code.cpp.controlflow.IRGuards + +query predicate astGuards(GuardCondition guard) { + any() +} + +query predicate astGuardsCompare(int startLine, string msg) { + exists(GuardCondition guard, Expr left, Expr right, int k, string which, string op | + exists(boolean sense | + sense = true and which = "true" + or sense = false and which = "false" + | + guard.comparesLt(left, right, k, true, sense) and op = " < " + or + guard.comparesLt(left, right, k, false, sense) and op = " >= " + or + guard.comparesEq(left, right, k, true, sense) and op = " == " + or + guard.comparesEq(left, right, k, false, sense) and op = " != " + ) + and startLine = guard.getLocation().getStartLine() + and msg = left + op + right + "+" + k + " when " + guard + " is " + which + ) +} + +query predicate astGuardsControl(GuardCondition guard, boolean sense, int start, int end) { + exists(BasicBlock block | + guard.controls(block, sense) and + block.hasLocationInfo(_, start, _, end, _) + ) +} + +query predicate astGuardsEnsure(GuardCondition guard, Expr left, string op, Expr right, int k, int start, int end) +{ + exists(BasicBlock block | + guard.ensuresLt(left, right, k, block, true) and op = "<" + or + guard.ensuresLt(left, right, k, block, false) and op = ">=" + or + guard.ensuresEq(left, right, k, block, true) and op = "==" + or + guard.ensuresEq(left, right, k, block, false) and op = "!=" + | + block.hasLocationInfo(_, start, _, end, _) + ) +} + +query predicate irGuards(IRGuardCondition guard) { + any() +} + +query predicate irGuardsCompare(int startLine, string msg) { + exists(IRGuardCondition guard, Instruction left, Instruction right, int k, string which, string op | + exists(boolean sense | + sense = true and which = "true" + or sense = false and which = "false" + | + guard.comparesLt(left, right, k, true, sense) and op = " < " + or + guard.comparesLt(left, right, k, false, sense) and op = " >= " + or + guard.comparesEq(left, right, k, true, sense) and op = " == " + or + guard.comparesEq(left, right, k, false, sense) and op = " != " + ) + and startLine = guard.getLocation().getStartLine() + and msg = left.getUnconvertedResultExpression() + op + right.getUnconvertedResultExpression() + "+" + k + " when " + guard + " is " + which + ) +} +query predicate irGuardsControl(IRGuardCondition guard, boolean sense, int start, int end) { + exists(IRBlock block | + guard.controls(block, sense) and + block.getLocation().hasLocationInfo(_, start, _, end, _) + ) +} + +query predicate irGuardsEnsure(IRGuardCondition guard, Instruction left, string op, Instruction right, int k, int start, int end) +{ + exists(IRBlock block | + guard.ensuresLt(left, right, k, block, true) and op = "<" + or + guard.ensuresLt(left, right, k, block, false) and op = ">=" + or + guard.ensuresEq(left, right, k, block, true) and op = "==" + or + guard.ensuresEq(left, right, k, block, false) and op = "!=" + | + block.getLocation().hasLocationInfo(_, start, _, end, _) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/XML.qll b/csharp/ql/src/semmle/code/csharp/XML.qll index 8b605b02508f..8e434aa7866d 100644 --- a/csharp/ql/src/semmle/code/csharp/XML.qll +++ b/csharp/ql/src/semmle/code/csharp/XML.qll @@ -1,5 +1,5 @@ /** - * 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.csharp.Element @@ -18,7 +18,7 @@ class XMLLocatable extends @xmllocatable { not this instanceof File // in the dbscheme } - /** The source location for this element. */ + /** Gets the source location for this element. */ Location getALocation() { xmllocations(this,result) } /** @@ -32,7 +32,7 @@ class XMLLocatable extends @xmllocatable { ) } - /** A printable representation of this element. */ + /** Gets a printable representation of this element. */ abstract string toString(); } @@ -42,46 +42,49 @@ 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,_,_) | @@ -90,18 +93,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() } } @@ -111,51 +111,52 @@ 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 XMLLocatable, @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) } + /** Gets a printable representation of this DTD. */ override string toString() { (this.isPublic() and result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + @@ -168,89 +169,87 @@ class XMLDTD extends XMLLocatable, @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. */ - override + /** 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. */ - override + /** 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 XMLLocatable, @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() = "" } override string toString() { @@ -261,13 +260,13 @@ class XMLNamespace extends XMLLocatable, @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() } } @@ -276,15 +275,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() } } diff --git a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll index a4e456839475..e545fc93f5d5 100644 --- a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll @@ -190,30 +190,40 @@ private Type elementType(RefType t) { ) } +private predicate upcastEnhancedForStmtAux(BaseSsaUpdate v, RefType t, RefType t1, RefType t2) { + exists(EnhancedForStmt for | + for.getVariable() = v.getDefiningExpr() and + v.getSourceVariable().getType().getErasure() = t2 and + t = boxIfNeeded(elementType(for.getExpr().getType())) and + t.getErasure() = t1 + ) +} + /** * Holds if `v` is the iteration variable of an enhanced for statement, `t` is * the type of the elements being iterated over, and this type is more precise * than the type of `v`. */ private predicate upcastEnhancedForStmt(BaseSsaUpdate v, RefType t) { - exists(EnhancedForStmt for, RefType t1, RefType t2 | - for.getVariable() = v.getDefiningExpr() and - v.getSourceVariable().getType().getErasure() = t2 and - t = boxIfNeeded(elementType(for.getExpr().getType())) and - t.getErasure() = t1 and + exists(RefType t1, RefType t2 | + upcastEnhancedForStmtAux(v, t, t1, t2) and t1.getASourceSupertype+() = t2 ) } +private predicate downcastSuccessorAux(CastExpr cast, BaseSsaVariable v, RefType t, RefType t1, RefType t2) { + cast.getExpr() = v.getAUse() and + t = cast.getType() and + t1 = t.getErasure() and + t2 = v.getSourceVariable().getType().getErasure() +} + /** * Holds if `va` is an access to a value that has previously been downcast to `t`. */ private predicate downcastSuccessor(VarAccess va, RefType t) { exists(CastExpr cast, BaseSsaVariable v, RefType t1, RefType t2 | - cast.getExpr() = v.getAUse() and - t = cast.getType() and - t1 = t.getErasure() and - t2 = v.getSourceVariable().getType().getErasure() and + downcastSuccessorAux(cast, v, t, t1, t2) and t1.getASourceSupertype+() = t2 and va = v.getAUse() and dominates(cast, va) and diff --git a/java/ql/src/semmle/code/xml/XML.qll b/java/ql/src/semmle/code/xml/XML.qll index 07fe3efa879a..5c49be9d14c8 100755 --- a/java/ql/src/semmle/code/xml/XML.qll +++ b/java/ql/src/semmle/code/xml/XML.qll @@ -70,9 +70,12 @@ class XMLParent extends @xmlparent { } /** + * 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 @@ -84,10 +87,7 @@ 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) } /** Gets the text value contained in this XML parent. */ diff --git a/javascript/externs/web/w3c_dom1.js b/javascript/externs/web/w3c_dom1.js index 6f43c00a3efc..bf85793fec6b 100644 --- a/javascript/externs/web/w3c_dom1.js +++ b/javascript/externs/web/w3c_dom1.js @@ -25,9 +25,11 @@ /** * @constructor + * @param {string=} message + * @param {string=} message * @see http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/level-one-core.html#ID-17189187 */ -function DOMException() {} +function DOMException(message, name) {} /** * @type {number} diff --git a/javascript/ql/src/semmle/javascript/XML.qll b/javascript/ql/src/semmle/javascript/XML.qll index c07e44294f58..bc7e8f2aaa2a 100755 --- a/javascript/ql/src/semmle/javascript/XML.qll +++ b/javascript/ql/src/semmle/javascript/XML.qll @@ -6,7 +6,7 @@ import javascript /** 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) } /** @@ -33,46 +33,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,_,_) | @@ -81,18 +84,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() } } @@ -102,46 +102,46 @@ 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() { result = File.super.getAbsolutePath() } - /** 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,_) } /** 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() + "' '" + @@ -157,37 +157,37 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { /** 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, _) } /** 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 } @@ -197,49 +197,49 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { 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,_,_,_,_) } /** 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,_) } /** 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()) @@ -248,13 +248,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() } } @@ -263,15 +263,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,_,_,_) } /** 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() } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 1e6e47d254d9..dd10f2039c3f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -614,6 +614,26 @@ module TaintTracking { } + /** + * A check of the form `if((x))`, which sanitizes `x` in its "then" branch. + * + * `` is a call with callee name 'safe', 'whitelist', 'allow', or similar. + * + * This sanitizer is not enabled by default. + */ + class AdHocWhitelistCheckSanitizer extends SanitizerGuardNode, DataFlow::CallNode { + AdHocWhitelistCheckSanitizer() { + getCalleeName().regexpMatch("(?i).*((? -1 | ExampleConfiguration | true | tst.js:220:19:220:19 | v | | tst.js:226:9:226:26 | -1 >= o.indexOf(v) | ExampleConfiguration | false | tst.js:226:25:226:25 | v | +| tst.js:236:9:236:24 | isWhitelisted(v) | ExampleConfiguration | true | tst.js:236:23:236:23 | v | +| tst.js:240:9:240:28 | config.allowValue(v) | ExampleConfiguration | true | tst.js:240:27:240:27 | v | diff --git a/javascript/ql/test/library-tests/TaintBarriers/TaintedSink.expected b/javascript/ql/test/library-tests/TaintBarriers/TaintedSink.expected index 1831db03e3d0..81935683df3e 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/TaintedSink.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/TaintedSink.expected @@ -34,3 +34,5 @@ | tst.js:215:14:215:14 | v | tst.js:199:13:199:20 | SOURCE() | | tst.js:223:14:223:14 | v | tst.js:199:13:199:20 | SOURCE() | | tst.js:227:14:227:14 | v | tst.js:199:13:199:20 | SOURCE() | +| tst.js:239:14:239:14 | v | tst.js:235:13:235:20 | SOURCE() | +| tst.js:243:14:243:14 | v | tst.js:235:13:235:20 | SOURCE() | diff --git a/javascript/ql/test/library-tests/TaintBarriers/isBarrier.expected b/javascript/ql/test/library-tests/TaintBarriers/isBarrier.expected index 530c48093f79..315e118a0837 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/isBarrier.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/isBarrier.expected @@ -29,3 +29,5 @@ | tst.js:217:14:217:14 | v | ExampleConfiguration | | tst.js:221:14:221:14 | v | ExampleConfiguration | | tst.js:229:14:229:14 | v | ExampleConfiguration | +| tst.js:237:14:237:14 | v | ExampleConfiguration | +| tst.js:241:14:241:14 | v | ExampleConfiguration | diff --git a/javascript/ql/test/library-tests/TaintBarriers/tst.js b/javascript/ql/test/library-tests/TaintBarriers/tst.js index c0d7179a7a08..ea0cc0951759 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/tst.js +++ b/javascript/ql/test/library-tests/TaintBarriers/tst.js @@ -230,3 +230,16 @@ function RelationalIndexOfCheckSanitizer () { } } + +function adhocWhitelisting() { + var v = SOURCE(); + if (isWhitelisted(v)) + SINK(v); + else + SINK(v); + if (config.allowValue(v)) + SINK(v); + else + SINK(v); + +} diff --git a/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.expected b/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.expected index dab5febc8e86..6425c04ab80d 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.expected @@ -14,4 +14,8 @@ | src/express.js:28:3:28:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:29:3:29:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:30:3:30:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:47:3:47:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:48:3:48:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:49:3:49:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:50:3:50:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/responseExprs.js:17:5:17:7 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RequestInputAccess.expected b/javascript/ql/test/library-tests/frameworks/Express/RequestInputAccess.expected index ebfd4b31eeb5..8c0b0b3b76c3 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RequestInputAccess.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RequestInputAccess.expected @@ -12,3 +12,7 @@ | src/express.js:28:3:28:16 | req.get("foo") | header | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:29:3:29:19 | req.header("bar") | header | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:30:3:30:13 | req.cookies | cookie | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:47:3:47:17 | req.headers.baz | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:48:3:48:10 | req.host | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:49:3:49:14 | req.hostname | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:50:3:50:32 | req.hea ... erName] | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.expected index 2751fe2b1618..babfdaa6bfa1 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.expected @@ -14,6 +14,7 @@ | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res | | src/express.js:37:12:37:32 | functio ... res){} | src/express.js:37:22:37:24 | req | src/express.js:37:27:37:29 | res | | src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:13:42:15 | req | src/express.js:42:18:42:20 | res | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.expected index aaf31f20eebd..e288c556b8c4 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.expected @@ -20,6 +20,7 @@ | src/express.js:34:14:34:52 | require ... handler | src/express.js:34:1:34:53 | app.get ... andler) | true | | src/express.js:39:9:39:20 | getHandler() | src/express.js:39:1:39:21 | app.use ... dler()) | false | | src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:44:1:44:26 | app.use ... dler()) | false | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | true | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | true | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | true | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | true | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.expected index d66b0b4915a7..e4bd32539d9a 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.expected @@ -16,3 +16,5 @@ | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:39:9:39:20 | getHandler() | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:39:9:39:20 | getHandler() | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:39:9:39:20 | getHandler() | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:44:9:44:25 | getArrowHandler() | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.expected index 2a46b11b1d7e..f4805a5e53e6 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.expected @@ -10,6 +10,7 @@ | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.expected index 893037fd8083..b7081b75823f 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.expected @@ -7,4 +7,5 @@ | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:40:27:40:48 | functio ... res) {} | | src/express.js:39:9:39:20 | getHandler() | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:16:19:18:3 | functio ... ");\\n } | +| src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/subrouter.js:4:19:4:25 | protect | src/subrouter.js:5:14:5:28 | makeSubRouter() | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.expected index a58a2cfa0ddc..63f85929c59c 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.expected @@ -7,4 +7,5 @@ | src/csurf-example.js:40:27:40:48 | functio ... res) {} | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:39:9:39:20 | getHandler() | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:44:9:44:25 | getArrowHandler() | | src/subrouter.js:5:14:5:28 | makeSubRouter() | src/subrouter.js:4:19:4:25 | protect | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.expected index f495f1c550a4..732a9e8391e2 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.expected @@ -14,4 +14,8 @@ | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:28:3:28:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:29:3:29:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:30:3:30:5 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:47:3:47:5 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:48:3:48:5 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:5 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:50:3:50:5 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:17:5:17:7 | req | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.expected index 0489f326ba1f..8112a1636a96 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.expected @@ -9,6 +9,7 @@ | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | false | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | false | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | false | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | false | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandler.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandler.expected index ce4218b05a86..7ed8331c31de 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandler.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandler.expected @@ -25,6 +25,7 @@ | src/express.js:39:1:39:21 | app.use ... dler()) | src/express.js:39:9:39:20 | getHandler() | | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:42:12:42:28 | (req, res) => f() | | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.expected index 8f3eefb0ef42..e788350ad5f2 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.expected @@ -20,6 +20,7 @@ | src/express.js:34:1:34:53 | app.get ... andler) | src/express.js:34:14:34:52 | require ... handler | | src/express.js:39:1:39:21 | app.use ... dler()) | src/express.js:39:9:39:20 | getHandler() | | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.expected index 8f3eefb0ef42..e788350ad5f2 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.expected @@ -20,6 +20,7 @@ | src/express.js:34:1:34:53 | app.get ... andler) | src/express.js:34:14:34:52 | require ... handler | | src/express.js:39:1:39:21 | app.use ... dler()) | src/express.js:39:9:39:20 | getHandler() | | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRequestMethod.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRequestMethod.expected index ff71b7d13f5e..ef656f126633 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRequestMethod.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRequestMethod.expected @@ -11,6 +11,7 @@ | src/express.js:16:3:18:4 | router. ... );\\n }) | GET | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | POST | | src/express.js:34:1:34:53 | app.get ... andler) | GET | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | POST | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | GET | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | GET | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | GET | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.expected index 226a3d59d097..61ae5da20308 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.expected @@ -20,6 +20,7 @@ | src/express.js:34:1:34:53 | app.get ... andler) | 0 | src/express.js:34:14:34:52 | require ... handler | | src/express.js:39:1:39:21 | app.use ... dler()) | 0 | src/express.js:39:9:39:20 | getHandler() | | src/express.js:44:1:44:26 | app.use ... dler()) | 0 | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | 0 | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | 0 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | 0 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | 0 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouter.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouter.expected index c29595cc07b9..46af44628f11 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouter.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouter.expected @@ -20,6 +20,7 @@ | src/express.js:34:1:34:53 | app.get ... andler) | src/express.js:2:11:2:19 | express() | | src/express.js:39:1:39:21 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.expected index 68bcc0d9b677..a37c24eeeda3 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.expected @@ -9,6 +9,7 @@ | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | +| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getARouteHandler.expected b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getARouteHandler.expected index 9ff5a646dd54..7a37c4c671e5 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getARouteHandler.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getARouteHandler.expected @@ -9,6 +9,7 @@ | src/express.js:2:11:2:19 | express() | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:2:11:2:19 | express() | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:2:11:2:19 | express() | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:2:11:2:19 | express() | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.expected b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.expected index 232ca3a54f9d..fd3766cb7b38 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.expected @@ -75,7 +75,14 @@ | src/express.js:2:11:2:19 | express() | src/express.js:44:5:44:7 | use | src/express.js:39:9:39:20 | getHandler() | | src/express.js:2:11:2:19 | express() | src/express.js:44:9:44:23 | getArrowHandler | src/express.js:39:9:39:20 | getHandler() | | src/express.js:2:11:2:19 | express() | src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:39:9:39:20 | getHandler() | -| src/express.js:2:11:2:19 | express() | src/express.js:45:1:45:0 | exit node of | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:46:1:46:3 | app | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:46:1:46:8 | app.post | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:46:1:51:3 | app.pos ... e];\\n}); | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:46:5:46:8 | post | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:46:10:46:19 | '/headers' | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:44:9:44:25 | getArrowHandler() | +| src/express.js:2:11:2:19 | express() | src/express.js:52:1:52:0 | exit node of | src/express.js:44:9:44:25 | getArrowHandler() | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:4:1:4:26 | app.use ... rotect) | src/subrouter.js:4:19:4:25 | protect | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:5:1:5:3 | app | src/subrouter.js:4:19:4:25 | protect | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:5:1:5:7 | app.use | src/subrouter.js:4:19:4:25 | protect | diff --git a/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.expected b/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.expected index e3cbcce77aaa..dfd0a7058130 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.expected @@ -9,6 +9,7 @@ | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:2:11:2:19 | express() | src/express.js:4:32:4:34 | req | src/express.js:4:37:4:39 | res | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:2:11:2:19 | express() | src/express.js:16:28:16:30 | req | src/express.js:16:33:16:35 | res | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:2:11:2:19 | express() | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:2:11:2:19 | express() | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 | diff --git a/javascript/ql/test/library-tests/frameworks/Express/isRequest.expected b/javascript/ql/test/library-tests/frameworks/Express/isRequest.expected index 34e47ad1c92c..d36af77ff644 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/isRequest.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/isRequest.expected @@ -14,4 +14,8 @@ | src/express.js:28:3:28:5 | req | | src/express.js:29:3:29:5 | req | | src/express.js:30:3:30:5 | req | +| src/express.js:47:3:47:5 | req | +| src/express.js:48:3:48:5 | req | +| src/express.js:49:3:49:5 | req | +| src/express.js:50:3:50:5 | req | | src/responseExprs.js:17:5:17:7 | req | diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/express.js b/javascript/ql/test/library-tests/frameworks/Express/src/express.js index ddbda24cd290..d60a18cde4fb 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/src/express.js +++ b/javascript/ql/test/library-tests/frameworks/Express/src/express.js @@ -42,3 +42,10 @@ function getArrowHandler() { return (req, res) => f(); } app.use(getArrowHandler()); + +app.post('/headers', function(req, res) { + req.headers.baz; + req.host; + req.hostname; + req.headers[config.headerName]; +});