Merge branch 'rc/1.23' into mergeback-123-ql

This commit is contained in:
james
2019-12-12 15:05:28 +00:00
31 changed files with 232 additions and 149 deletions

View File

@@ -23,6 +23,8 @@
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/BitwiseSignCheck.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/BitwiseSignCheck.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/SignedOverflowCheck.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/PointerOverflow.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/NestedLoopSameVar.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/NestedLoopSameVar.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/UseInOwnInitializer.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/UseInOwnInitializer.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Critical/NewArrayDeleteMismatch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Critical/NewArrayDeleteMismatch.ql: /Correctness/Common Errors

View File

@@ -24,6 +24,8 @@
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/BitwiseSignCheck.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/BitwiseSignCheck.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/SignedOverflowCheck.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/PointerOverflow.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/NestedLoopSameVar.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/NestedLoopSameVar.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/UseInOwnInitializer.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/UseInOwnInitializer.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Critical/NewArrayDeleteMismatch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Critical/NewArrayDeleteMismatch.ql: /Correctness/Common Errors

View File

@@ -11,13 +11,13 @@ cached
private newtype TOperand = private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TNonPhiMemoryOperand( TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) { ) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TPhiOperand( TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
@@ -25,28 +25,6 @@ private newtype TOperand =
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
} }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = Construction::getRegisterOperandDefinition(instr, _)
or
result = Construction::getMemoryOperandDefinition(instr, _, _)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
private predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr
}
/** /**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction. * A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/ */

View File

@@ -133,6 +133,16 @@ private module Cached {
overlap instanceof MustExactlyOverlap overlap instanceof MustExactlyOverlap
} }
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* For performance reasons, this predicate is not implemented (never holds)
* for the SSA stages of the IR.
*/
cached
predicate isInCycle(Instruction instr) { none() }
cached cached
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) { Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |

View File

@@ -11,13 +11,13 @@ cached
private newtype TOperand = private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TNonPhiMemoryOperand( TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) { ) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TPhiOperand( TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
@@ -25,28 +25,6 @@ private newtype TOperand =
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
} }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = Construction::getRegisterOperandDefinition(instr, _)
or
result = Construction::getMemoryOperandDefinition(instr, _, _)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
private predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr
}
/** /**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction. * A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/ */

View File

@@ -93,6 +93,29 @@ private module Cached {
overlap instanceof MustTotallyOverlap overlap instanceof MustTotallyOverlap
} }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = getRegisterOperandDefinition(instr, _)
or
result = getMemoryOperandDefinition(instr, _, _)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
cached
predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr
}
cached cached
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as

View File

@@ -684,9 +684,17 @@ abstract class TranslatedElement extends TTranslatedElement {
* Gets the temporary variable generated by this element with tag `tag`. * Gets the temporary variable generated by this element with tag `tag`.
*/ */
final IRTempVariable getTempVariable(TempVariableTag tag) { final IRTempVariable getTempVariable(TempVariableTag tag) {
result.getAST() = getAST() and exists(Locatable ast |
result.getTag() = tag and result.getAST() = ast and
hasTempVariable(tag, _) result.getTag() = tag and
hasTempVariableAndAST(tag, ast)
)
}
pragma[noinline]
private predicate hasTempVariableAndAST(TempVariableTag tag, Locatable ast) {
hasTempVariable(tag, _) and
ast = getAST()
} }
/** /**

View File

@@ -11,13 +11,13 @@ cached
private newtype TOperand = private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TNonPhiMemoryOperand( TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) { ) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TPhiOperand( TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
@@ -25,28 +25,6 @@ private newtype TOperand =
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
} }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = Construction::getRegisterOperandDefinition(instr, _)
or
result = Construction::getMemoryOperandDefinition(instr, _, _)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
private predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr
}
/** /**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction. * A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/ */

View File

@@ -133,6 +133,16 @@ private module Cached {
overlap instanceof MustExactlyOverlap overlap instanceof MustExactlyOverlap
} }
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* For performance reasons, this predicate is not implemented (never holds)
* for the SSA stages of the IR.
*/
cached
predicate isInCycle(Instruction instr) { none() }
cached cached
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) { Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |

View File

@@ -1765,7 +1765,7 @@ module Ssa {
* *
* The write is live because of the implicit entry definition `def`, which can be * The write is live because of the implicit entry definition `def`, which can be
* reached using one or more calls (as indicated by `additionalCalls`), starting * reached using one or more calls (as indicated by `additionalCalls`), starting
* from call `c`. That is, data can flow from the write at index `i` into the the * from call `c`. That is, data can flow from the write at index `i` into the
* callable containing `def`. * callable containing `def`.
* *
* Example: * Example:
@@ -2329,7 +2329,7 @@ module Ssa {
* ``` * ```
* *
* If this definition is the update of `i` on line 5, then the value may be read inside * If this definition is the update of `i` on line 5, then the value may be read inside
* `M2` via the the call on line 6. * `M2` via the call on line 6.
*/ */
predicate isCapturedVariableDefinitionFlowIn( predicate isCapturedVariableDefinitionFlowIn(
ImplicitEntryDefinition def, ControlFlow::Nodes::ElementNode c, boolean additionalCalls ImplicitEntryDefinition def, ControlFlow::Nodes::ElementNode c, boolean additionalCalls
@@ -2356,7 +2356,7 @@ module Ssa {
* ``` * ```
* *
* If this definition is the update of `i` on line 4, then the value may be read outside * If this definition is the update of `i` on line 4, then the value may be read outside
* of `M2` via the the call on line 5. * of `M2` via the call on line 5.
*/ */
predicate isCapturedVariableDefinitionFlowOut( predicate isCapturedVariableDefinitionFlowOut(
ImplicitCallDefinition cdef, boolean additionalCalls ImplicitCallDefinition cdef, boolean additionalCalls

View File

@@ -11,13 +11,13 @@ cached
private newtype TOperand = private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TNonPhiMemoryOperand( TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) { ) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TPhiOperand( TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
@@ -25,28 +25,6 @@ private newtype TOperand =
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
} }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = Construction::getRegisterOperandDefinition(instr, _)
or
result = Construction::getMemoryOperandDefinition(instr, _, _)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
private predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr
}
/** /**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction. * A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/ */

View File

@@ -95,6 +95,29 @@ private module Cached {
.getInstructionOperand(getInstructionTag(instruction), tag) .getInstructionOperand(getInstructionTag(instruction), tag)
} }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = getRegisterOperandDefinition(instr, _)
or
result = getMemoryOperandDefinition(instr, _, _)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
cached
predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr
}
cached cached
CSharpType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { CSharpType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as

View File

@@ -11,13 +11,13 @@ cached
private newtype TOperand = private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TNonPhiMemoryOperand( TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) { ) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
not isInCycle(useInstr) not Construction::isInCycle(useInstr)
} or } or
TPhiOperand( TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
@@ -25,28 +25,6 @@ private newtype TOperand =
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
} }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = Construction::getRegisterOperandDefinition(instr, _)
or
result = Construction::getMemoryOperandDefinition(instr, _, _)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
private predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr
}
/** /**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction. * A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/ */

View File

@@ -133,6 +133,16 @@ private module Cached {
overlap instanceof MustExactlyOverlap overlap instanceof MustExactlyOverlap
} }
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* For performance reasons, this predicate is not implemented (never holds)
* for the SSA stages of the IR.
*/
cached
predicate isInCycle(Instruction instr) { none() }
cached cached
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) { Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |

View File

@@ -0,0 +1,87 @@
Query writing: common performance issues
========================================
This topic offers some simple tips on how to avoid common problems that can affect the performance of your queries.
Before reading the tips below, it is worth reiterating a few important points about CodeQL and the QL language:
- CodeQL `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ are evaluated to database `tables <https://en.wikipedia.org/wiki/Table_(database)>`__. Large predicates generate large tables with many rows, and are therefore expensive to compute.
- The QL language is implemented using standard database operations and `relational algebra <https://en.wikipedia.org/wiki/Relational_algebra>`__ (such as join, projection, and union). For further information about query languages and databases, see :doc:`About QL <../about-ql>`.
- Queries are evaluated *bottom-up*, which means that a predicate is not evaluated until *all* of the predicates that it depends on are evaluated. For more information on query evaluation, see `Evaluation of QL programs <https://help.semmle.com/QL/ql-handbook/evaluation.html>`__ in the QL handbook.
Performance tips
----------------
Follow the guidelines below to ensure that you don't get tripped up by the most common CodeQL performance pitfalls.
Eliminate cartesian products
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The performance of a predicate can often be judged by considering roughly how many results it has.
One way of creating badly performing predicates is by using two variables without relating them in any way, or only relating them using a negation.
This leads to computing the `Cartesian product <https://en.wikipedia.org/wiki/Cartesian_product>`__ between the sets of possible values for each variable, potentially generating a huge table of results.
This can occur if you don't specify restrictions on your variables.
For instance, consider the following predicate that checks whether a Java method ``m`` may access a field ``f``::
predicate mayAccess(Method m, Field f) {
f.getAnAccess().getEnclosingCallable() = m
or
not exists(m.getBody())
}
The predicate holds if ``m`` contains an access to ``f``, but also conservatively assumes that methods without bodies (for example, native methods) may access *any* field.
However, if ``m`` is a native method, the table computed by ``mayAccess`` will contain a row ``m, f`` for *all* fields ``f`` in the codebase, making it potentially very large.
This example shows a similar mistake in a member predicate::
class Foo extends Class {
...
// BAD! Does not use this
Method getToString() {
result.getName() = "ToString"
}
...
}
Note that while ``getToString()`` does not declare any parameters, it has two implicit parameters, ``result`` and ``this``, which it fails to relate. Therefore, the table computed by ``getToString()`` contains a row for every combination of ``result`` and ``this``. That is, a row for every combination of a method named ``"ToString"`` and an instance of ``Foo``.
To avoid making this mistake, ``this`` should be restricted in the member predicate ``getToString()`` on the class ``Foo``.
Use specific types
~~~~~~~~~~~~~~~~~~
`Types <https://help.semmle.com/QL/ql-handbook/types.html>`__ provide an upper bound on the size of a relation.
This helps the query optimizer be more effective, so it's generally good to use the most specific types possible. For example::
predicate foo(LoggingCall e)
is preferred over::
predicate foo(Expr e)
From the type context, the query optimizer deduces that some parts of the program are redundant and removes them, or *specializes* them.
Avoid complex recursion
~~~~~~~~~~~~~~~~~~~~~~~
`Recursion <https://help.semmle.com/QL/ql-handbook/recursion.html>`__ is about self-referencing definitions.
It can be extremely powerful as long as it is used appropriately.
On the whole, you should try to make recursive predicates as simple as possible.
That is, you should define a *base case* that allows the predicate to *bottom out*, along with a single *recursive call*::
int depth(Stmt s) {
exists(Callable c | c.getBody() = s | result = 0) // base case
or
result = depth(s.getParent()) + 1 // recursive call
}
.. pull-quote:: Note
The query optimizer has special data structures for dealing with `transitive closures <https://help.semmle.com/QL/ql-handbook/recursion.html#transitive-closures>`__.
If possible, use a transitive closure over a simple recursive predicate, as it is likely to be computed faster.
Further information
-------------------
- Find out more about QL in the `QL language handbook <https://help.semmle.com/QL/ql-handbook/index.html>`__ and `QL language specification <https://help.semmle.com/QL/ql-spec/language.html>`__.

View File

@@ -15,6 +15,7 @@ Information for query writers
../intro-to-data-flow ../intro-to-data-flow
select-statement select-statement
../locations ../locations
debugging-queries
Visit `Learning CodeQL <https://help.semmle.com/QL/learn-ql/>`__ to find basic information about CodeQL. This includes information about the underlying query language QL, as well as help and advice on writing queries for specific programming languages. Visit `Learning CodeQL <https://help.semmle.com/QL/learn-ql/>`__ to find basic information about CodeQL. This includes information about the underlying query language QL, as well as help and advice on writing queries for specific programming languages.

View File

@@ -1667,6 +1667,15 @@ li > ul > li {
margin-bottom: 0; margin-bottom: 0;
} }
.admonition.note ol {
width: 90%;
margin-left: 2.2em;
}
.admonition.note ol > li {
margin-top: 0.5em;
}
/* /*
* extra styles for more appropriate for syntax highlighting * extra styles for more appropriate for syntax highlighting
* *

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `ChakraCore database <https://downloads.lgtm.com/snapshots/cpp/microsoft/chakracore/ChakraCore-revision-2017-April-12--18-13-26.zip>`__ - `ChakraCore database <https://downloads.lgtm.com/snapshots/cpp/microsoft/chakracore/ChakraCore-revision-2017-April-12--18-13-26.zip>`__
.. note:: .. note::

View File

@@ -13,7 +13,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `ChakraCore database <https://downloads.lgtm.com/snapshots/cpp/microsoft/chakracore/ChakraCore-revision-2017-April-12--18-13-26.zip>`__ - `ChakraCore database <https://downloads.lgtm.com/snapshots/cpp/microsoft/chakracore/ChakraCore-revision-2017-April-12--18-13-26.zip>`__
.. note:: .. note::

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `dotnet/coreclr database <http://downloads.lgtm.com/snapshots/cpp/dotnet/coreclr/dotnet_coreclr_fbe0c77.zip>`__ - `dotnet/coreclr database <http://downloads.lgtm.com/snapshots/cpp/dotnet/coreclr/dotnet_coreclr_fbe0c77.zip>`__
.. note:: .. note::

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `dotnet/coreclr database <http://downloads.lgtm.com/snapshots/cpp/dotnet/coreclr/dotnet_coreclr_fbe0c77.zip>`__ - `dotnet/coreclr database <http://downloads.lgtm.com/snapshots/cpp/dotnet/coreclr/dotnet_coreclr_fbe0c77.zip>`__
.. note:: .. note::

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `exiv2 database <http://downloads.lgtm.com/snapshots/cpp/exiv2/Exiv2_exiv2_b090f4d.zip>`__ - `exiv2 database <http://downloads.lgtm.com/snapshots/cpp/exiv2/Exiv2_exiv2_b090f4d.zip>`__
.. note:: .. note::

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `rsyslog database <https://downloads.lgtm.com/snapshots/cpp/rsyslog/rsyslog/rsyslog-all-revision-2018-April-27--14-12-31.zip>`__ - `rsyslog database <https://downloads.lgtm.com/snapshots/cpp/rsyslog/rsyslog/rsyslog-all-revision-2018-April-27--14-12-31.zip>`__
.. note:: .. note::

View File

@@ -15,7 +15,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__ - `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__
.. note:: .. note::

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `VIVO Vitro database <http://downloads.lgtm.com/snapshots/java/vivo-project/Vitro/vivo-project_Vitro_java-srcVersion_47ae42c01954432c3c3b92d5d163551ce367f510-dist_odasa-lgtm-2019-04-23-7ceff95-linux64.zip>`__ - `VIVO Vitro database <http://downloads.lgtm.com/snapshots/java/vivo-project/Vitro/vivo-project_Vitro_java-srcVersion_47ae42c01954432c3c3b92d5d163551ce367f510-dist_odasa-lgtm-2019-04-23-7ceff95-linux64.zip>`__
.. note:: .. note::

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__ - `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__
.. note:: .. note::

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__ - `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__
.. note:: .. note::
@@ -105,8 +105,8 @@ Each query library also implicitly defines a module.
.. note:: .. note::
Queries are always contained in query files with the file extension ``.ql``. `Quick queries <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/quick-query.html>`__, run in `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/home-page.html>`__, are no exception: the quick query window maintains a temporary QL file in the background. Queries are always contained in query files with the file extension ``.ql``.
Parts of queries can be lifted into `library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension ``.qll``. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements. Parts of queries can be lifted into `library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension ``.qll``. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later. Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.

View File

@@ -11,7 +11,7 @@ Setup
For this example you should download: For this example you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__ - `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `VIVO Vitro database <http://downloads.lgtm.com/snapshots/java/vivo-project/Vitro/vivo-project_Vitro_java-srcVersion_47ae42c01954432c3c3b92d5d163551ce367f510-dist_odasa-lgtm-2019-04-23-7ceff95-linux64.zip>`__ - `VIVO Vitro database <http://downloads.lgtm.com/snapshots/java/vivo-project/Vitro/vivo-project_Vitro_java-srcVersion_47ae42c01954432c3c3b92d5d163551ce367f510-dist_odasa-lgtm-2019-04-23-7ceff95-linux64.zip>`__
.. note:: .. note::

View File

@@ -1 +1,9 @@
Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been addedthe CodeQL database available to download above is based on an historical version of the codebase. You can download the database as a zip file by clicking the link on the slide above. To use the database in CodeQL for Visual Studio Code:
#. Unzip the file
#. Add the unzipped database to Visual Studio Code
#. Upgrade the database if necessary
For further information, see `Using the extension <https://help.semmle.com/codeql/codeql-for-vscode/procedures/using-extension.html>`__ in the CodeQL for Visual Studio Code help.
Note that results generated in the query console are likely to differ to those generated in CodeQL for Visual Studio Code as LGTM.com analyzes the most recent revisions of each project that has been addedthe CodeQL database available to download above is based on an historical version of the codebase.

View File

@@ -109,7 +109,7 @@ Analysis overview
Queries are written in `QL <https://semmle.com/ql>`__ and usually depend on one or more of the `standard CodeQL libraries <https://github.com/semmle/ql>`__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developers machine. Queries are written in `QL <https://semmle.com/ql>`__ and usually depend on one or more of the `standard CodeQL libraries <https://github.com/semmle/ql>`__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developers machine.
Query results can be interpreted and presented in a variety of ways, including displaying them in an `IDE plugin <https://lgtm.com/help/lgtm/running-queries-ide>`__ such as QL for Eclipse, or in a web dashboard as on `LGTM <https://lgtm.com/help/lgtm/about-lgtm>`__. Query results can be interpreted and presented in a variety of ways, including displaying them in an `IDE extension <https://lgtm.com/help/lgtm/running-queries-ide>`__ such as CodeQL for Visual Studio Code, or in a web dashboard as on `LGTM <https://lgtm.com/help/lgtm/about-lgtm>`__.
Introducing QL Introducing QL
============== ==============

View File

@@ -5,14 +5,14 @@ GNU extensions (up to GCC 8.3),
Microsoft extensions (up to VS 2019), Microsoft extensions (up to VS 2019),
Arm Compiler 5.0 [2]_.","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``" Arm Compiler 5.0 [2]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``"
C#,C# up to 7.3. with .NET up to 4.8 [3]_.,"Microsoft Visual Studio up to 2019, C#,C# up to 8.0. with .NET up to 4.8 [3]_,"Microsoft Visual Studio up to 2019,
.NET Core up to 2.2","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" .NET Core up to 3.0","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
Go (aka Golang), "Go up to 1.13", "Go 1.11 or more recent", ``.go`` Go (aka Golang), "Go up to 1.13", "Go 1.11 or more recent", ``.go``
Java,"Java 6 to 12 [4]_.","javac (OpenJDK and Oracle JDK), Java,"Java 6 to 13 [4]_","javac (OpenJDK and Oracle JDK),
Eclipse compiler for Java (ECJ) [5]_.",``.java`` Eclipse compiler for Java (ECJ) [5]_",``.java``
JavaScript,ECMAScript 2019 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_." JavaScript,ECMAScript 2019 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_"
Python,"2.7, 3.5, 3.6, 3.7",Not applicable,``.py`` Python,"2.7, 3.5, 3.6, 3.7, 3.8",Not applicable,``.py``
TypeScript [7]_.,"2.6-3.5",Standard TypeScript compiler,"``.ts``, ``.tsx``" TypeScript [7]_,"2.6-3.7",Standard TypeScript compiler,"``.ts``, ``.tsx``"
1 Language Variants Compilers Extensions
5 Java Java 6 to 12 [4]_. Java 6 to 13 [4]_ javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [5]_. javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [5]_ ``.java``
6 JavaScript ECMAScript 2019 or lower Not applicable ``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_. ``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_
7 Python 2.7, 3.5, 3.6, 3.7 2.7, 3.5, 3.6, 3.7, 3.8 Not applicable ``.py``
8 TypeScript [7]_. TypeScript [7]_ 2.6-3.5 2.6-3.7 Standard TypeScript compiler ``.ts``, ``.tsx``
9
10
11
12
13
14
15
16
17
18