mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge remote-tracking branch 'upstream/master' into typeAheadSink
This commit is contained in:
@@ -7,6 +7,9 @@
|
||||
- [typeahead.js](https://www.npmjs.com/package/typeahead.js)
|
||||
- [Handlebars](https://www.npmjs.com/package/handlebars)
|
||||
|
||||
- Imports with the `.js` extension can now be resolved to a TypeScript file,
|
||||
when the import refers to a file generated by TypeScript.
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|
||||
@@ -143,6 +143,11 @@
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll"
|
||||
],
|
||||
"IR SSASanity": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll"
|
||||
],
|
||||
"C++ IR InstructionImports": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll",
|
||||
|
||||
@@ -13,14 +13,20 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
* A variable referenced by the IR for a function. The variable may be a user-declared variable
|
||||
* (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation
|
||||
* (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
class IRVariable extends TIRVariable {
|
||||
Language::Function func;
|
||||
|
||||
abstract string toString();
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _)
|
||||
}
|
||||
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Language::AST getAST();
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
string getUniqueId() { none() }
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -72,7 +78,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
@@ -97,20 +103,34 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
* namespace-scope variables, static fields, and static local variables.
|
||||
*/
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
@@ -119,10 +139,19 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
abstract class IRGeneratedVariable extends IRVariable {
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
@@ -144,6 +173,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
TempVariableTag tag;
|
||||
|
||||
@@ -158,18 +192,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa
|
||||
override string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the return value of a function.
|
||||
*/
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
|
||||
@@ -94,12 +94,21 @@ module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount = strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,26 +6,6 @@ private import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* bytes:bits.
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(int bits) { result = (bits / 8).toString() + ":" + (bits % 8).toString() }
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if Ints::hasValue(bitOffset)
|
||||
then
|
||||
if bitOffset >= 0
|
||||
then result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset))
|
||||
else result = "+?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of field `field` in bits.
|
||||
*/
|
||||
@@ -137,7 +117,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction))
|
||||
exists(PointerOffsetInstruction ptrOffset |
|
||||
ptrOffset = instr and
|
||||
operand = ptrOffset.getLeftOperand() and
|
||||
bitOffset = getPointerBitOffset(ptrOffset)
|
||||
)
|
||||
or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
|
||||
@@ -865,3 +865,17 @@ private module CachedForDebugging {
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
}
|
||||
|
||||
module SSASanity {
|
||||
query predicate multipleOperandMemoryLocations(
|
||||
OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText
|
||||
) {
|
||||
exists(int locationCount |
|
||||
locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and
|
||||
locationCount > 1 and
|
||||
func = operand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction()) and
|
||||
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @name Aliased SSA Sanity Check
|
||||
* @description Performs sanity checks on the SSA construction. This query should have no results.
|
||||
* @kind table
|
||||
* @id cpp/aliased-ssa-sanity-check
|
||||
*/
|
||||
|
||||
import SSASanity
|
||||
@@ -0,0 +1,2 @@
|
||||
private import SSAConstruction as SSA
|
||||
import SSA::SSASanity
|
||||
@@ -13,14 +13,20 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
* A variable referenced by the IR for a function. The variable may be a user-declared variable
|
||||
* (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation
|
||||
* (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
class IRVariable extends TIRVariable {
|
||||
Language::Function func;
|
||||
|
||||
abstract string toString();
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _)
|
||||
}
|
||||
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Language::AST getAST();
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
string getUniqueId() { none() }
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -72,7 +78,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
@@ -97,20 +103,34 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
* namespace-scope variables, static fields, and static local variables.
|
||||
*/
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
@@ -119,10 +139,19 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
abstract class IRGeneratedVariable extends IRVariable {
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
@@ -144,6 +173,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
TempVariableTag tag;
|
||||
|
||||
@@ -158,18 +192,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa
|
||||
override string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the return value of a function.
|
||||
*/
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
|
||||
@@ -94,12 +94,21 @@ module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount = strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,14 +13,20 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
* A variable referenced by the IR for a function. The variable may be a user-declared variable
|
||||
* (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation
|
||||
* (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
class IRVariable extends TIRVariable {
|
||||
Language::Function func;
|
||||
|
||||
abstract string toString();
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _)
|
||||
}
|
||||
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Language::AST getAST();
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
string getUniqueId() { none() }
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -72,7 +78,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
@@ -97,20 +103,34 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
* namespace-scope variables, static fields, and static local variables.
|
||||
*/
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
@@ -119,10 +139,19 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
abstract class IRGeneratedVariable extends IRVariable {
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
@@ -144,6 +173,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
TempVariableTag tag;
|
||||
|
||||
@@ -158,18 +192,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa
|
||||
override string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the return value of a function.
|
||||
*/
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
|
||||
@@ -94,12 +94,21 @@ module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount = strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,26 +6,6 @@ private import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* bytes:bits.
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(int bits) { result = (bits / 8).toString() + ":" + (bits % 8).toString() }
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if Ints::hasValue(bitOffset)
|
||||
then
|
||||
if bitOffset >= 0
|
||||
then result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset))
|
||||
else result = "+?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of field `field` in bits.
|
||||
*/
|
||||
@@ -137,7 +117,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction))
|
||||
exists(PointerOffsetInstruction ptrOffset |
|
||||
ptrOffset = instr and
|
||||
operand = ptrOffset.getLeftOperand() and
|
||||
bitOffset = getPointerBitOffset(ptrOffset)
|
||||
)
|
||||
or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
|
||||
@@ -865,3 +865,17 @@ private module CachedForDebugging {
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
}
|
||||
|
||||
module SSASanity {
|
||||
query predicate multipleOperandMemoryLocations(
|
||||
OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText
|
||||
) {
|
||||
exists(int locationCount |
|
||||
locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and
|
||||
locationCount > 1 and
|
||||
func = operand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction()) and
|
||||
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @name Unaliased SSA Sanity Check
|
||||
* @description Performs sanity checks on the SSA construction. This query should have no results.
|
||||
* @kind table
|
||||
* @id cpp/unaliased-ssa-sanity-check
|
||||
*/
|
||||
|
||||
import SSASanity
|
||||
@@ -0,0 +1,2 @@
|
||||
private import SSAConstruction as SSA
|
||||
import SSA::SSASanity
|
||||
@@ -192,3 +192,33 @@ predicate isGT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a > b }
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isGE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a >= b }
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* "bytes:bits". If `bits` represents an integer number of bytes, the ":bits" section is omitted.
|
||||
* If `bits` does not have a known value, the result is "?".
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(IntValue bits) {
|
||||
exists(int bytes, int leftoverBits |
|
||||
hasValue(bits) and
|
||||
bytes = bits / 8 and
|
||||
leftoverBits = bits % 8 and
|
||||
if leftoverBits = 0 then result = bytes.toString() else result = bytes + ":" + leftoverBits
|
||||
)
|
||||
or
|
||||
not hasValue(bits) and result = "?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if hasValue(bitOffset)
|
||||
then
|
||||
if bitOffset >= 0
|
||||
then result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else result = "-" + bitsToBytesAndBits(neg(bitOffset))
|
||||
else result = "+?"
|
||||
}
|
||||
|
||||
@@ -30,5 +30,5 @@ Overlap getOverlap(IntValue defStart, IntValue defEnd, IntValue useStart, IntVal
|
||||
bindingset[start, end]
|
||||
string getIntervalString(IntValue start, IntValue end) {
|
||||
// We represent an interval has half-open, so print it as "[start..end)".
|
||||
result = "[" + intValueToString(start) + ".." + intValueToString(end) + ")"
|
||||
result = "[" + bitsToBytesAndBits(start) + ".." + bitsToBytesAndBits(end) + ")"
|
||||
}
|
||||
|
||||
@@ -1,86 +1,86 @@
|
||||
| escape.cpp:111:18:111:21 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:115:20:115:23 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:116:19:116:28 | PointerSub[4] | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:116:20:116:23 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:117:23:117:26 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:118:9:118:12 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:120:12:120:15 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:123:14:123:17 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:124:15:124:18 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:127:9:127:12 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:129:12:129:15 | CopyValue | no_+0:0 | no_+0:0 |
|
||||
| escape.cpp:134:5:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||
| escape.cpp:134:11:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||
| escape.cpp:135:5:135:12 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||
| escape.cpp:135:5:135:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||
| escape.cpp:136:5:136:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||
| escape.cpp:136:7:136:14 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||
| escape.cpp:137:17:137:24 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||
| escape.cpp:137:17:137:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||
| escape.cpp:138:17:138:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||
| escape.cpp:138:19:138:26 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||
| escape.cpp:140:21:140:32 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 |
|
||||
| escape.cpp:140:21:140:32 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||
| escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
|
||||
| escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 |
|
||||
| escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||
| escape.cpp:143:19:143:27 | CopyValue | no_Point+0:0 | no_Point+0:0 |
|
||||
| escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||
| escape.cpp:144:6:144:14 | CopyValue | no_Point+0:0 | no_Point+0:0 |
|
||||
| escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||
| escape.cpp:145:20:145:30 | CopyValue | no_Point+8:0 | no_Point+8:0 |
|
||||
| escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
|
||||
| escape.cpp:146:5:146:18 | CopyValue | no_Point+8:0 | no_Point+8:0 |
|
||||
| escape.cpp:146:7:146:17 | CopyValue | no_Point+8:0 | no_Point+8:0 |
|
||||
| escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
|
||||
| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
|
||||
| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
|
||||
| escape.cpp:149:16:149:16 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 |
|
||||
| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
|
||||
| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
|
||||
| escape.cpp:150:29:150:29 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 |
|
||||
| escape.cpp:151:5:151:14 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
|
||||
| escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
|
||||
| escape.cpp:152:19:152:28 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
|
||||
| escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
|
||||
| escape.cpp:155:17:155:30 | CopyValue | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 |
|
||||
| escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 |
|
||||
| escape.cpp:158:17:158:28 | CopyValue | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 |
|
||||
| escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 |
|
||||
| escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0:0 | no_ssa_refToArrayElement+0:0 |
|
||||
| escape.cpp:161:19:161:45 | CopyValue | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
|
||||
| escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
|
||||
| escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
|
||||
| escape.cpp:164:24:164:40 | CopyValue | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 |
|
||||
| escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 |
|
||||
| escape.cpp:167:19:167:28 | CopyValue | passByPtr+0:0 | passByPtr+0:0 |
|
||||
| escape.cpp:170:21:170:29 | CopyValue | passByRef+0:0 | passByRef+0:0 |
|
||||
| escape.cpp:173:22:173:38 | CopyValue | no_ssa_passByPtr+0:0 | no_ssa_passByPtr+0:0 |
|
||||
| escape.cpp:176:24:176:39 | CopyValue | no_ssa_passByRef+0:0 | no_ssa_passByRef+0:0 |
|
||||
| escape.cpp:179:22:179:42 | CopyValue | no_ssa_passByPtr_ret+0:0 | no_ssa_passByPtr_ret+0:0 |
|
||||
| escape.cpp:182:24:182:43 | CopyValue | no_ssa_passByRef_ret+0:0 | no_ssa_passByRef_ret+0:0 |
|
||||
| escape.cpp:185:30:185:40 | CopyValue | passByPtr2+0:0 | passByPtr2+0:0 |
|
||||
| escape.cpp:188:32:188:41 | CopyValue | passByRef2+0:0 | passByRef2+0:0 |
|
||||
| escape.cpp:191:30:191:42 | Call | none | passByPtr3+0:0 |
|
||||
| escape.cpp:191:44:191:54 | CopyValue | passByPtr3+0:0 | passByPtr3+0:0 |
|
||||
| escape.cpp:194:32:194:46 | Call | none | passByRef3+0:0 |
|
||||
| escape.cpp:194:32:194:59 | CopyValue | none | passByRef3+0:0 |
|
||||
| escape.cpp:194:48:194:57 | CopyValue | passByRef3+0:0 | passByRef3+0:0 |
|
||||
| escape.cpp:199:17:199:34 | CopyValue | no_ssa_passByPtr4+0:0 | no_ssa_passByPtr4+0:0 |
|
||||
| escape.cpp:199:37:199:54 | CopyValue | no_ssa_passByPtr5+0:0 | no_ssa_passByPtr5+0:0 |
|
||||
| escape.cpp:202:5:202:19 | Call | none | passByRef6+0:0 |
|
||||
| escape.cpp:202:5:202:32 | CopyValue | none | passByRef6+0:0 |
|
||||
| escape.cpp:202:21:202:30 | CopyValue | passByRef6+0:0 | passByRef6+0:0 |
|
||||
| escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0:0 |
|
||||
| escape.cpp:205:5:205:39 | CopyValue | none | no_ssa_passByRef7+0:0 |
|
||||
| escape.cpp:205:21:205:37 | CopyValue | no_ssa_passByRef7+0:0 | no_ssa_passByRef7+0:0 |
|
||||
| escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0:0 |
|
||||
| escape.cpp:217:14:217:16 | CopyValue | c2+0:0 | c2+0:0 |
|
||||
| escape.cpp:221:8:221:19 | Call | none | c3+0:0 |
|
||||
| escape.cpp:225:17:225:28 | Call | none | c4+0:0 |
|
||||
| escape.cpp:247:2:247:27 | Store | condEscape1+0:0 | condEscape1+0:0 |
|
||||
| escape.cpp:247:16:247:27 | CopyValue | condEscape1+0:0 | condEscape1+0:0 |
|
||||
| escape.cpp:249:9:249:34 | Store | condEscape2+0:0 | condEscape2+0:0 |
|
||||
| escape.cpp:249:23:249:34 | CopyValue | condEscape2+0:0 | condEscape2+0:0 |
|
||||
| escape.cpp:111:18:111:21 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0 | no_+0 |
|
||||
| escape.cpp:115:20:115:23 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:116:19:116:28 | PointerSub[4] | no_+0 | no_+0 |
|
||||
| escape.cpp:116:20:116:23 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0 | no_+0 |
|
||||
| escape.cpp:117:23:117:26 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:118:9:118:12 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:120:12:120:15 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:123:14:123:17 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:124:15:124:18 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:127:9:127:12 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:129:12:129:15 | CopyValue | no_+0 | no_+0 |
|
||||
| escape.cpp:134:5:134:18 | Convert | no_Array+0 | no_Array+0 |
|
||||
| escape.cpp:134:11:134:18 | Convert | no_Array+0 | no_Array+0 |
|
||||
| escape.cpp:135:5:135:12 | Convert | no_Array+0 | no_Array+0 |
|
||||
| escape.cpp:135:5:135:15 | PointerAdd[4] | no_Array+20 | no_Array+20 |
|
||||
| escape.cpp:136:5:136:15 | PointerAdd[4] | no_Array+20 | no_Array+20 |
|
||||
| escape.cpp:136:7:136:14 | Convert | no_Array+0 | no_Array+0 |
|
||||
| escape.cpp:137:17:137:24 | Convert | no_Array+0 | no_Array+0 |
|
||||
| escape.cpp:137:17:137:27 | PointerAdd[4] | no_Array+20 | no_Array+20 |
|
||||
| escape.cpp:138:17:138:27 | PointerAdd[4] | no_Array+20 | no_Array+20 |
|
||||
| escape.cpp:138:19:138:26 | Convert | no_Array+0 | no_Array+0 |
|
||||
| escape.cpp:140:21:140:32 | FieldAddress[x] | no_Point+0 | no_Point+0 |
|
||||
| escape.cpp:140:21:140:32 | FieldAddress[y] | no_Point+4 | no_Point+4 |
|
||||
| escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8 | no_Point+8 |
|
||||
| escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0 | no_Point+0 |
|
||||
| escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4 | no_Point+4 |
|
||||
| escape.cpp:143:19:143:27 | CopyValue | no_Point+0 | no_Point+0 |
|
||||
| escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4 | no_Point+4 |
|
||||
| escape.cpp:144:6:144:14 | CopyValue | no_Point+0 | no_Point+0 |
|
||||
| escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4 | no_Point+4 |
|
||||
| escape.cpp:145:20:145:30 | CopyValue | no_Point+8 | no_Point+8 |
|
||||
| escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8 | no_Point+8 |
|
||||
| escape.cpp:146:5:146:18 | CopyValue | no_Point+8 | no_Point+8 |
|
||||
| escape.cpp:146:7:146:17 | CopyValue | no_Point+8 | no_Point+8 |
|
||||
| escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8 | no_Point+8 |
|
||||
| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0 | no_Derived+0 |
|
||||
| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0 | no_Derived+0 |
|
||||
| escape.cpp:149:16:149:16 | FieldAddress[b] | no_Derived+0 | no_Derived+0 |
|
||||
| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0 | no_Derived+0 |
|
||||
| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0 | no_Derived+0 |
|
||||
| escape.cpp:150:29:150:29 | FieldAddress[b] | no_Derived+0 | no_Derived+0 |
|
||||
| escape.cpp:151:5:151:14 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12 | no_Derived+12 |
|
||||
| escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16 | no_Derived+16 |
|
||||
| escape.cpp:152:19:152:28 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12 | no_Derived+12 |
|
||||
| escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16 | no_Derived+16 |
|
||||
| escape.cpp:155:17:155:30 | CopyValue | no_ssa_addrOf+0 | no_ssa_addrOf+0 |
|
||||
| escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0 | no_ssa_addrOf+0 |
|
||||
| escape.cpp:158:17:158:28 | CopyValue | no_ssa_refTo+0 | no_ssa_refTo+0 |
|
||||
| escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0 | no_ssa_refTo+0 |
|
||||
| escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0 | no_ssa_refToArrayElement+0 |
|
||||
| escape.cpp:161:19:161:45 | CopyValue | no_ssa_refToArrayElement+20 | no_ssa_refToArrayElement+20 |
|
||||
| escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20 | no_ssa_refToArrayElement+20 |
|
||||
| escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20 | no_ssa_refToArrayElement+20 |
|
||||
| escape.cpp:164:24:164:40 | CopyValue | no_ssa_refToArray+0 | no_ssa_refToArray+0 |
|
||||
| escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0 | no_ssa_refToArray+0 |
|
||||
| escape.cpp:167:19:167:28 | CopyValue | passByPtr+0 | passByPtr+0 |
|
||||
| escape.cpp:170:21:170:29 | CopyValue | passByRef+0 | passByRef+0 |
|
||||
| escape.cpp:173:22:173:38 | CopyValue | no_ssa_passByPtr+0 | no_ssa_passByPtr+0 |
|
||||
| escape.cpp:176:24:176:39 | CopyValue | no_ssa_passByRef+0 | no_ssa_passByRef+0 |
|
||||
| escape.cpp:179:22:179:42 | CopyValue | no_ssa_passByPtr_ret+0 | no_ssa_passByPtr_ret+0 |
|
||||
| escape.cpp:182:24:182:43 | CopyValue | no_ssa_passByRef_ret+0 | no_ssa_passByRef_ret+0 |
|
||||
| escape.cpp:185:30:185:40 | CopyValue | passByPtr2+0 | passByPtr2+0 |
|
||||
| escape.cpp:188:32:188:41 | CopyValue | passByRef2+0 | passByRef2+0 |
|
||||
| escape.cpp:191:30:191:42 | Call | none | passByPtr3+0 |
|
||||
| escape.cpp:191:44:191:54 | CopyValue | passByPtr3+0 | passByPtr3+0 |
|
||||
| escape.cpp:194:32:194:46 | Call | none | passByRef3+0 |
|
||||
| escape.cpp:194:32:194:59 | CopyValue | none | passByRef3+0 |
|
||||
| escape.cpp:194:48:194:57 | CopyValue | passByRef3+0 | passByRef3+0 |
|
||||
| escape.cpp:199:17:199:34 | CopyValue | no_ssa_passByPtr4+0 | no_ssa_passByPtr4+0 |
|
||||
| escape.cpp:199:37:199:54 | CopyValue | no_ssa_passByPtr5+0 | no_ssa_passByPtr5+0 |
|
||||
| escape.cpp:202:5:202:19 | Call | none | passByRef6+0 |
|
||||
| escape.cpp:202:5:202:32 | CopyValue | none | passByRef6+0 |
|
||||
| escape.cpp:202:21:202:30 | CopyValue | passByRef6+0 | passByRef6+0 |
|
||||
| escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0 |
|
||||
| escape.cpp:205:5:205:39 | CopyValue | none | no_ssa_passByRef7+0 |
|
||||
| escape.cpp:205:21:205:37 | CopyValue | no_ssa_passByRef7+0 | no_ssa_passByRef7+0 |
|
||||
| escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0 |
|
||||
| escape.cpp:217:14:217:16 | CopyValue | c2+0 | c2+0 |
|
||||
| escape.cpp:221:8:221:19 | Call | none | c3+0 |
|
||||
| escape.cpp:225:17:225:28 | Call | none | c4+0 |
|
||||
| escape.cpp:247:2:247:27 | Store | condEscape1+0 | condEscape1+0 |
|
||||
| escape.cpp:247:16:247:27 | CopyValue | condEscape1+0 | condEscape1+0 |
|
||||
| escape.cpp:249:9:249:34 | Store | condEscape2+0 | condEscape2+0 |
|
||||
| escape.cpp:249:23:249:34 | CopyValue | condEscape2+0 | condEscape2+0 |
|
||||
|
||||
@@ -4,6 +4,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as Raw
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis as UnAA
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Un
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction
|
||||
import semmle.code.cpp.ir.internal.IntegerConstant
|
||||
|
||||
from Raw::Instruction rawInstr, Un::Instruction unInstr, string rawPointsTo, string unPointsTo
|
||||
where
|
||||
@@ -12,21 +13,21 @@ where
|
||||
(
|
||||
exists(Variable var, int rawBitOffset, int unBitOffset |
|
||||
RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), rawBitOffset) and
|
||||
rawPointsTo = var.toString() + RawAA::getBitOffsetString(rawBitOffset) and
|
||||
rawPointsTo = var.toString() + getBitOffsetString(rawBitOffset) and
|
||||
UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), unBitOffset) and
|
||||
unPointsTo = var.toString() + UnAA::getBitOffsetString(unBitOffset)
|
||||
unPointsTo = var.toString() + getBitOffsetString(unBitOffset)
|
||||
)
|
||||
or
|
||||
exists(Variable var, int unBitOffset |
|
||||
not RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), _) and
|
||||
rawPointsTo = "none" and
|
||||
UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), unBitOffset) and
|
||||
unPointsTo = var.toString() + UnAA::getBitOffsetString(unBitOffset)
|
||||
unPointsTo = var.toString() + getBitOffsetString(unBitOffset)
|
||||
)
|
||||
or
|
||||
exists(Variable var, int rawBitOffset |
|
||||
RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), rawBitOffset) and
|
||||
rawPointsTo = var.toString() + RawAA::getBitOffsetString(rawBitOffset) and
|
||||
rawPointsTo = var.toString() + getBitOffsetString(rawBitOffset) and
|
||||
not UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), _) and
|
||||
unPointsTo = "none"
|
||||
)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql
|
||||
@@ -13,14 +13,20 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
* A variable referenced by the IR for a function. The variable may be a user-declared variable
|
||||
* (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation
|
||||
* (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
class IRVariable extends TIRVariable {
|
||||
Language::Function func;
|
||||
|
||||
abstract string toString();
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _)
|
||||
}
|
||||
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Language::AST getAST();
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
string getUniqueId() { none() }
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -72,7 +78,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
@@ -97,20 +103,34 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
* namespace-scope variables, static fields, and static local variables.
|
||||
*/
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
@@ -119,10 +139,19 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
abstract class IRGeneratedVariable extends IRVariable {
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
@@ -144,6 +173,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
TempVariableTag tag;
|
||||
|
||||
@@ -158,18 +192,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa
|
||||
override string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the return value of a function.
|
||||
*/
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
|
||||
@@ -94,12 +94,21 @@ module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount = strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,14 +13,20 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
* A variable referenced by the IR for a function. The variable may be a user-declared variable
|
||||
* (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation
|
||||
* (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
class IRVariable extends TIRVariable {
|
||||
Language::Function func;
|
||||
|
||||
abstract string toString();
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _)
|
||||
}
|
||||
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Language::AST getAST();
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
string getUniqueId() { none() }
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -72,7 +78,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
@@ -97,20 +103,34 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
* namespace-scope variables, static fields, and static local variables.
|
||||
*/
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
@@ -119,10 +139,19 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
abstract class IRGeneratedVariable extends IRVariable {
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
@@ -144,6 +173,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
TempVariableTag tag;
|
||||
|
||||
@@ -158,18 +192,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa
|
||||
override string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the return value of a function.
|
||||
*/
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
|
||||
@@ -94,12 +94,21 @@ module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount = strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -865,3 +865,17 @@ private module CachedForDebugging {
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
}
|
||||
|
||||
module SSASanity {
|
||||
query predicate multipleOperandMemoryLocations(
|
||||
OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText
|
||||
) {
|
||||
exists(int locationCount |
|
||||
locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and
|
||||
locationCount > 1 and
|
||||
func = operand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction()) and
|
||||
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @name Unaliased SSA Sanity Check
|
||||
* @description Performs sanity checks on the SSA construction. This query should have no results.
|
||||
* @kind table
|
||||
* @id csharp/unaliased-ssa-sanity-check
|
||||
*/
|
||||
|
||||
import SSASanity
|
||||
@@ -0,0 +1,2 @@
|
||||
private import SSAConstruction as SSA
|
||||
import SSA::SSASanity
|
||||
@@ -192,3 +192,33 @@ predicate isGT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a > b }
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isGE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a >= b }
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* "bytes:bits". If `bits` represents an integer number of bytes, the ":bits" section is omitted.
|
||||
* If `bits` does not have a known value, the result is "?".
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(IntValue bits) {
|
||||
exists(int bytes, int leftoverBits |
|
||||
hasValue(bits) and
|
||||
bytes = bits / 8 and
|
||||
leftoverBits = bits % 8 and
|
||||
if leftoverBits = 0 then result = bytes.toString() else result = bytes + ":" + leftoverBits
|
||||
)
|
||||
or
|
||||
not hasValue(bits) and result = "?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if hasValue(bitOffset)
|
||||
then
|
||||
if bitOffset >= 0
|
||||
then result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else result = "-" + bitsToBytesAndBits(neg(bitOffset))
|
||||
else result = "+?"
|
||||
}
|
||||
|
||||
@@ -30,5 +30,5 @@ Overlap getOverlap(IntValue defStart, IntValue defEnd, IntValue useStart, IntVal
|
||||
bindingset[start, end]
|
||||
string getIntervalString(IntValue start, IntValue end) {
|
||||
// We represent an interval has half-open, so print it as "[start..end)".
|
||||
result = "[" + intValueToString(start) + ".." + intValueToString(end) + ")"
|
||||
result = "[" + bitsToBytesAndBits(start) + ".." + bitsToBytesAndBits(end) + ")"
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql
|
||||
@@ -113,7 +113,7 @@ Alert queries (`@kind problem` or `path-problem`) support two further properties
|
||||
* `low `
|
||||
* `medium `
|
||||
* `high `
|
||||
* `very high`
|
||||
* `very-high`
|
||||
* `@problem.severity`–defines the level of severity of the alert:
|
||||
* `error`–an issue that is likely to cause incorrect program behavior, for example a crash or vulnerability.
|
||||
* `warning`–an issue that indicates a potential problem in the code, or makes the code fragile if another (unrelated) part of code is changed.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* external/cwe/cwe-088
|
||||
*/
|
||||
|
||||
import semmle.code.java.Expr
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.ExternalProcess
|
||||
import ExecCommon
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* external/cwe/cwe-088
|
||||
*/
|
||||
|
||||
import semmle.code.java.Expr
|
||||
import java
|
||||
import semmle.code.java.security.ExternalProcess
|
||||
import ExecCommon
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
|
||||
import semmle.code.java.Expr
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import SqlInjectionLib
|
||||
import DataFlow::PathGraph
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.SqlUnescapedLib
|
||||
import SqlInjectionLib
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ predicate benignContext(Expr e) {
|
||||
any(InvokeExpr invoke).getCallee() = e
|
||||
or
|
||||
// arguments to Promise.resolve (and promise library variants) are benign.
|
||||
e = any(ResolvedPromiseDefinition promise).getValue().asExpr()
|
||||
e = any(PromiseCreationCall promise).getValue().asExpr()
|
||||
}
|
||||
|
||||
predicate oneshotClosure(DataFlow::CallNode call) {
|
||||
@@ -198,7 +198,7 @@ module Deferred {
|
||||
/**
|
||||
* A resolved promise created by a `new Deferred().resolve()` call.
|
||||
*/
|
||||
class ResolvedDeferredPromiseDefinition extends ResolvedPromiseDefinition {
|
||||
class ResolvedDeferredPromiseDefinition extends PromiseCreationCall {
|
||||
ResolvedDeferredPromiseDefinition() {
|
||||
this = any(DeferredPromiseDefinition def).ref().getAMethodCall("resolve")
|
||||
}
|
||||
|
||||
@@ -83,9 +83,13 @@ abstract class Module extends TopLevel {
|
||||
result = c.(Folder).getJavaScriptFile("index")
|
||||
)
|
||||
or
|
||||
// handle the case where the import path is missing an extension
|
||||
// handle the case where the import path is missing the extension
|
||||
exists(Folder f | f = path.resolveUpTo(path.getNumComponent() - 1) |
|
||||
result = f.getJavaScriptFile(path.getBaseName())
|
||||
or
|
||||
// If a js file was not found look for a file that compiles to js
|
||||
not exists(f.getJavaScriptFile(path.getBaseName())) and
|
||||
result = f.getJavaScriptFile(path.getStem())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -205,6 +205,9 @@ abstract class PathExpr extends PathExprBase {
|
||||
/** Gets the base name of the folder or file this path refers to. */
|
||||
string getBaseName() { result = getValue().(PathString).getBaseName() }
|
||||
|
||||
/** Gets the stem, that is, base name without extension, of the folder or file this path refers to. */
|
||||
string getStem() { result = getValue().(PathString).getStem() }
|
||||
|
||||
/**
|
||||
* Gets the file or folder that the first `n` components of this path refer to
|
||||
* when resolved relative to the root folder of the given `priority`.
|
||||
|
||||
@@ -30,6 +30,22 @@ module Bluebird {
|
||||
|
||||
override DataFlow::Node getValue() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An aggregated promise produced either by `Promise.all`, `Promise.race` or `Promise.map`.
|
||||
*/
|
||||
class AggregateBluebirdPromiseDefinition extends PromiseCreationCall {
|
||||
AggregateBluebirdPromiseDefinition() {
|
||||
exists(string m | m = "all" or m = "race" or m = "map" |
|
||||
this = bluebird().getAMemberCall(m)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getValue() {
|
||||
result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -152,15 +152,20 @@ private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNo
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that is resolved with the given value.
|
||||
* A promise that is created and resolved with one or more value.
|
||||
*/
|
||||
abstract class ResolvedPromiseDefinition extends DataFlow::CallNode {
|
||||
abstract class PromiseCreationCall extends DataFlow::CallNode {
|
||||
/**
|
||||
* Gets the value this promise is resolved with.
|
||||
*/
|
||||
abstract DataFlow::Node getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that is created using a `.resolve()` call.
|
||||
*/
|
||||
abstract class ResolvedPromiseDefinition extends PromiseCreationCall {}
|
||||
|
||||
/**
|
||||
* A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function.
|
||||
*/
|
||||
@@ -172,6 +177,21 @@ class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition {
|
||||
override DataFlow::Node getValue() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An aggregated promise produced either by `Promise.all` or `Promise.race`.
|
||||
*/
|
||||
class AggregateES2015PromiseDefinition extends PromiseCreationCall {
|
||||
AggregateES2015PromiseDefinition() {
|
||||
exists(string m | m = "all" or m = "race" |
|
||||
this = DataFlow::globalVarRef("Promise").getAMemberCall(m)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getValue() {
|
||||
result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow edge from a promise reaction to the corresponding handler.
|
||||
*/
|
||||
@@ -197,7 +217,7 @@ predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0)
|
||||
or
|
||||
// from `x` to `Promise.resolve(x)`
|
||||
pred = succ.(ResolvedPromiseDefinition).getValue()
|
||||
pred = succ.(PromiseCreationCall).getValue()
|
||||
or
|
||||
exists(DataFlow::MethodCallNode thn, DataFlow::FunctionNode cb |
|
||||
thn.getMethodName() = "then" and cb = thn.getCallback(0)
|
||||
|
||||
@@ -840,16 +840,18 @@ module DataFlow {
|
||||
* An array element pattern viewed as a property read; for instance, in
|
||||
* `var [ x, y ] = arr`, `x` is a read of property 0 of `arr` and similar
|
||||
* for `y`.
|
||||
*
|
||||
* Note: We currently do not expose the array index as the property name,
|
||||
* instead treating it as a read of an unknown property.
|
||||
*/
|
||||
private class ElementPatternAsPropRead extends PropRead, ElementPatternNode {
|
||||
override Node getBase() { result = TDestructuringPatternNode(pattern) }
|
||||
|
||||
override Expr getPropertyNameExpr() { none() }
|
||||
|
||||
override string getPropertyName() { none() }
|
||||
override string getPropertyName() {
|
||||
exists (int i |
|
||||
elt = pattern.getElement(i) and
|
||||
result = i.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -211,7 +211,7 @@ private class WindowNameAccess extends RemoteFlowSource {
|
||||
this = DataFlow::globalObjectRef().getAPropertyRead("name")
|
||||
or
|
||||
// Reference to `name` on a container that does not assign to it.
|
||||
this.accessesGlobal("name") and
|
||||
this.asExpr().(GlobalVarAccess).getName() = "name" and
|
||||
not exists(VarDef def |
|
||||
def.getAVariable().(GlobalVariable).getName() = "name" and
|
||||
def.getContainer() = this.asExpr().getContainer()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { foo } from "./f.js";
|
||||
|
||||
foo();
|
||||
@@ -6,6 +6,7 @@ test_ImportSpecifiers
|
||||
| f.ts:1:8:1:8 | g | f.ts:1:8:1:8 | g |
|
||||
| g.ts:1:9:1:11 | foo | g.ts:1:9:1:11 | foo |
|
||||
| import-in-mjs.mjs:1:8:1:24 | exported_from_mjs | import-in-mjs.mjs:1:8:1:24 | exported_from_mjs |
|
||||
| import-ts-with-js-extension.ts:1:10:1:12 | foo | import-ts-with-js-extension.ts:1:10:1:12 | foo |
|
||||
| m/c.js:1:8:1:13 | * as b | m/c.js:1:13:1:13 | b |
|
||||
| tst.html:5:10:5:10 | f | tst.html:5:10:5:10 | f |
|
||||
| unresolved.js:1:8:1:8 | f | unresolved.js:1:8:1:8 | f |
|
||||
@@ -43,6 +44,7 @@ test_getImportedName
|
||||
| f.ts:1:8:1:8 | g | default |
|
||||
| g.ts:1:9:1:11 | foo | foo |
|
||||
| import-in-mjs.mjs:1:8:1:24 | exported_from_mjs | default |
|
||||
| import-ts-with-js-extension.ts:1:10:1:12 | foo | foo |
|
||||
| tst.html:5:10:5:10 | f | default |
|
||||
| unresolved.js:1:8:1:8 | f | default |
|
||||
test_ExportDeclarations
|
||||
@@ -65,6 +67,7 @@ test_getAnImportedModule
|
||||
| es2015_require.js | d.js |
|
||||
| f.ts | e.js |
|
||||
| g.ts | f.ts |
|
||||
| import-ts-with-js-extension.ts | f.ts |
|
||||
| m/c.js | b.js |
|
||||
test_getSourceNode
|
||||
| a.js:1:1:3:1 | export ... n 23;\\n} | default | a.js:1:16:3:1 | functio ... n 23;\\n} |
|
||||
@@ -87,6 +90,7 @@ test_Imports
|
||||
| f.ts:1:1:1:19 | import g from './e' | f.ts:1:15:1:19 | './e' | 1 |
|
||||
| g.ts:1:1:1:23 | import ... m './f' | g.ts:1:19:1:23 | './f' | 1 |
|
||||
| import-in-mjs.mjs:1:1:1:46 | import ... n-mjs'; | import-in-mjs.mjs:1:31:1:45 | 'export-in-mjs' | 1 |
|
||||
| import-ts-with-js-extension.ts:1:1:1:29 | import ... /f.js"; | import-ts-with-js-extension.ts:1:21:1:28 | "./f.js" | 1 |
|
||||
| m/c.js:1:1:1:26 | import ... '../b'; | m/c.js:1:20:1:25 | '../b' | 1 |
|
||||
| tst.html:5:3:5:20 | import f from 'a'; | tst.html:5:17:5:19 | 'a' | 1 |
|
||||
| unresolved.js:1:1:1:18 | import f from 'a'; | unresolved.js:1:15:1:17 | 'a' | 1 |
|
||||
@@ -94,6 +98,7 @@ test_NamedImportSpecifier
|
||||
| d.js:1:10:1:21 | default as g |
|
||||
| d.js:1:24:1:29 | x as y |
|
||||
| g.ts:1:9:1:11 | foo |
|
||||
| import-ts-with-js-extension.ts:1:10:1:12 | foo |
|
||||
test_GlobalVariableRef
|
||||
| a.js:5:31:5:31 | o |
|
||||
| exports.js:3:9:3:15 | exports |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_ResolvedPromiseDefinition(
|
||||
ResolvedPromiseDefinition resolved, DataFlow::Node res
|
||||
PromiseCreationCall resolved, DataFlow::Node res
|
||||
) {
|
||||
res = resolved.getValue()
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ test_getAPropertyRead
|
||||
| tst.js:34:6:34:12 | vvv.ppp | tst.js:34:6:34:16 | vvv.ppp.qqq |
|
||||
| tst.js:44:3:44:9 | console | tst.js:44:3:44:13 | console.log |
|
||||
| tst.js:44:15:44:17 | obj | tst.js:44:15:44:20 | obj[p] |
|
||||
| tst.js:46:17:46:21 | array | tst.js:47:10:47:10 | x |
|
||||
| tst.js:46:17:46:21 | array | tst.js:47:13:47:13 | y |
|
||||
| tst.js:46:17:46:21 | array | tst.js:47:16:47:16 | z |
|
||||
test_getAPropertyReference
|
||||
| classes.ts:3:21:3:20 | this | classes.ts:4:3:4:24 | instanc ... foo(); |
|
||||
| classes.ts:8:3:8:2 | this | classes.ts:8:15:8:35 | public ... erField |
|
||||
@@ -50,6 +53,9 @@ test_getAPropertyReference
|
||||
| tst.js:41:12:41:30 | ["a", ...arr3, "d"] | tst.js:41:27:41:29 | "d" |
|
||||
| tst.js:44:3:44:9 | console | tst.js:44:3:44:13 | console.log |
|
||||
| tst.js:44:15:44:17 | obj | tst.js:44:15:44:20 | obj[p] |
|
||||
| tst.js:46:17:46:21 | array | tst.js:47:10:47:10 | x |
|
||||
| tst.js:46:17:46:21 | array | tst.js:47:13:47:13 | y |
|
||||
| tst.js:46:17:46:21 | array | tst.js:47:16:47:16 | z |
|
||||
test_getAPropertySource
|
||||
| classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:19:4:23 | foo() |
|
||||
| classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:22:8:35 | parameterField |
|
||||
@@ -92,6 +98,9 @@ test_getAPropertyRead2
|
||||
| tst.js:34:6:34:8 | vvv | ppp | tst.js:34:6:34:12 | vvv.ppp |
|
||||
| tst.js:34:6:34:12 | vvv.ppp | qqq | tst.js:34:6:34:16 | vvv.ppp.qqq |
|
||||
| tst.js:44:3:44:9 | console | log | tst.js:44:3:44:13 | console.log |
|
||||
| tst.js:46:17:46:21 | array | 0 | tst.js:47:10:47:10 | x |
|
||||
| tst.js:46:17:46:21 | array | 1 | tst.js:47:13:47:13 | y |
|
||||
| tst.js:46:17:46:21 | array | 2 | tst.js:47:16:47:16 | z |
|
||||
test_getAPropertyReference2
|
||||
| classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:3:4:24 | instanc ... foo(); |
|
||||
| classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:15:8:35 | public ... erField |
|
||||
@@ -116,6 +125,9 @@ test_getAPropertyReference2
|
||||
| tst.js:34:6:34:8 | vvv | ppp | tst.js:34:6:34:12 | vvv.ppp |
|
||||
| tst.js:34:6:34:12 | vvv.ppp | qqq | tst.js:34:6:34:16 | vvv.ppp.qqq |
|
||||
| tst.js:44:3:44:9 | console | log | tst.js:44:3:44:13 | console.log |
|
||||
| tst.js:46:17:46:21 | array | 0 | tst.js:47:10:47:10 | x |
|
||||
| tst.js:46:17:46:21 | array | 1 | tst.js:47:13:47:13 | y |
|
||||
| tst.js:46:17:46:21 | array | 2 | tst.js:47:16:47:16 | z |
|
||||
test_hasPropertyWrite
|
||||
| classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:19:4:23 | foo() |
|
||||
| classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:22:8:35 | parameterField |
|
||||
|
||||
@@ -42,3 +42,8 @@ var arr1 = ["a", "b", "c"],
|
||||
|
||||
for (var p in obj)
|
||||
console.log(obj[p]);
|
||||
|
||||
function test(array) {
|
||||
let [x, y, z] = array;
|
||||
}
|
||||
|
||||
@@ -309,12 +309,10 @@ nodes
|
||||
| tst.js:277:22:277:29 | location |
|
||||
| tst.js:277:22:277:29 | location |
|
||||
| tst.js:282:9:282:29 | tainted |
|
||||
| tst.js:282:9:282:29 | tainted |
|
||||
| tst.js:282:19:282:29 | window.name |
|
||||
| tst.js:282:19:282:29 | window.name |
|
||||
| tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:297:35:297:42 | location |
|
||||
| tst.js:297:35:297:42 | location |
|
||||
| tst.js:297:35:297:42 | location |
|
||||
@@ -610,11 +608,8 @@ edges
|
||||
| tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location |
|
||||
| tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:282:19:282:29 | window.name | tst.js:282:9:282:29 | tainted |
|
||||
| tst.js:282:19:282:29 | window.name | tst.js:282:9:282:29 | tainted |
|
||||
| tst.js:285:59:285:65 | tainted | tst.js:285:59:285:65 | tainted |
|
||||
| tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location |
|
||||
| typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target |
|
||||
| typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search |
|
||||
@@ -709,9 +704,7 @@ edges
|
||||
| tst.js:257:7:257:10 | name | tst.js:257:7:257:10 | name | tst.js:257:7:257:10 | name | Cross-site scripting vulnerability due to $@. | tst.js:257:7:257:10 | name | user-provided value |
|
||||
| tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | Cross-site scripting vulnerability due to $@. | tst.js:261:11:261:21 | window.name | user-provided value |
|
||||
| tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location | Cross-site scripting vulnerability due to $@. | tst.js:277:22:277:29 | location | user-provided value |
|
||||
| tst.js:285:59:285:65 | tainted | tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:282:9:282:29 | tainted | user-provided value |
|
||||
| tst.js:285:59:285:65 | tainted | tst.js:282:19:282:29 | window.name | tst.js:285:59:285:65 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:282:19:282:29 | window.name | user-provided value |
|
||||
| tst.js:285:59:285:65 | tainted | tst.js:285:59:285:65 | tainted | tst.js:285:59:285:65 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:285:59:285:65 | tainted | user-provided value |
|
||||
| tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location | Cross-site scripting vulnerability due to $@. | tst.js:297:35:297:42 | location | user-provided value |
|
||||
| typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:38 | document.location | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:38 | document.location | user-provided value |
|
||||
| v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value |
|
||||
|
||||
@@ -88,6 +88,8 @@
|
||||
}
|
||||
|
||||
new Deferred().resolve(onlySideEffects()); // OK
|
||||
|
||||
Promise.all([onlySideEffects(), onlySideEffects()])
|
||||
})();
|
||||
|
||||
+function() {
|
||||
@@ -104,4 +106,4 @@ class Bar extends Foo {
|
||||
constructor() {
|
||||
console.log(super()); // OK.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use,
|
||||
exists(Expr mod |
|
||||
use.getEnclosingModule() = enclosing.getScope() and
|
||||
not use.getScope+() instanceof Function and
|
||||
mod.pointsTo(m)
|
||||
mod.pointsTo(m) and
|
||||
not is_annotation_with_from_future_import_annotations(use)
|
||||
|
|
||||
// either 'M.foo'
|
||||
use.(Attribute).getObject() = mod and use.(Attribute).getName() = attr
|
||||
@@ -70,6 +71,30 @@ predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `use` appears inside an annotation.
|
||||
*/
|
||||
predicate is_used_in_annotation(Expr use) {
|
||||
exists(FunctionExpr f |
|
||||
f.getReturns().getASubExpression*() = use or
|
||||
f.getArgs().getAnAnnotation().getASubExpression*() = use
|
||||
)
|
||||
or
|
||||
exists(AnnAssign a | a.getAnnotation().getASubExpression*() = use)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `use` appears as a subexpression of an annotation, _and_ if the
|
||||
* postponed evaluation of annotations presented in PEP 563 is in effect.
|
||||
* See https://www.python.org/dev/peps/pep-0563/
|
||||
*/
|
||||
predicate is_annotation_with_from_future_import_annotations(Expr use) {
|
||||
exists(ImportMember i | i.getScope() = use.getEnclosingModule() |
|
||||
i.getModule().pointsTo().getName() = "__future__" and i.getName() = "annotations"
|
||||
) and
|
||||
is_used_in_annotation(use)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether importing module 'first' before importing module 'other' will fail at runtime, due to an
|
||||
* AttributeError at 'use' (in module 'other') caused by 'first.attr' not being defined as its definition can
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| module3.py:8:23:8:33 | Attribute | 'Bar' may not be defined if module $@ is imported before module $@, as the $@ of Bar occurs after the cyclic $@ of module3. | module4.py:0:0:0:0 | Module module4 | module4 | module3.py:0:0:0:0 | Module module3 | module3 | module4.py:7:7:7:9 | ControlFlowNode for Bar | definition | module4.py:4:1:4:14 | Import | import |
|
||||
| module4.py:8:30:8:40 | Attribute | 'Foo' may not be defined if module $@ is imported before module $@, as the $@ of Foo occurs after the cyclic $@ of module4. | module3.py:0:0:0:0 | Module module3 | module3 | module4.py:0:0:0:0 | Module module4 | module4 | module3.py:7:7:7:9 | ControlFlowNode for Foo | definition | module3.py:4:1:4:14 | Import | import |
|
||||
@@ -0,0 +1 @@
|
||||
Imports/ModuleLevelCyclicImport.ql
|
||||
@@ -0,0 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import typing
|
||||
|
||||
import module2
|
||||
|
||||
@dataclasses.dataclass()
|
||||
class Foo:
|
||||
bars: typing.List[module2.Bar]
|
||||
@@ -0,0 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import typing
|
||||
|
||||
import module1
|
||||
|
||||
@dataclasses.dataclass()
|
||||
class Bar:
|
||||
def is_in_foo(self, foo: module1.Foo):
|
||||
return self in foo.bars
|
||||
@@ -0,0 +1,8 @@
|
||||
import dataclasses
|
||||
import typing
|
||||
|
||||
import module4
|
||||
|
||||
@dataclasses.dataclass()
|
||||
class Foo:
|
||||
bars: typing.List[module4.Bar]
|
||||
@@ -0,0 +1,9 @@
|
||||
import dataclasses
|
||||
import typing
|
||||
|
||||
import module3
|
||||
|
||||
@dataclasses.dataclass()
|
||||
class Bar:
|
||||
def is_in_foo(self, foo: module3.Foo):
|
||||
return self in foo.bars
|
||||
Reference in New Issue
Block a user