mirror of
https://github.com/github/codeql.git
synced 2026-07-20 18:58:36 +02:00
Merge pull request #2008 from dave-bartolomeo/dave/IRType2
C++: Implement language-neutral IR type system
This commit is contained in:
@@ -610,7 +610,9 @@ class FloatingPointType extends ArithmeticType {
|
||||
(
|
||||
kind >= 24 and kind <= 32
|
||||
or
|
||||
kind = 38
|
||||
kind >= 38 and kind <= 42
|
||||
or
|
||||
kind >= 45 and kind <= 50
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -540,6 +540,13 @@ class ErrorExpr extends Expr, @errorexpr {
|
||||
*/
|
||||
class AssumeExpr extends Expr, @assume {
|
||||
override string toString() { result = "__assume(...)" }
|
||||
|
||||
override string getCanonicalQLClass() { result = "AssumeExpr" }
|
||||
|
||||
/**
|
||||
* Gets the operand of the `__assume` expressions.
|
||||
*/
|
||||
Expr getOperand() { this.hasChild(result, 0) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
247
cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
Normal file
247
cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* Minimal, language-neutral type system for the IR.
|
||||
*/
|
||||
|
||||
private import internal.IRTypeInternal
|
||||
|
||||
private newtype TIRType =
|
||||
TIRVoidType() or
|
||||
TIRUnknownType() or
|
||||
TIRErrorType() { Language::hasErrorType() } or
|
||||
TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or
|
||||
TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or
|
||||
TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or
|
||||
TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or
|
||||
TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or
|
||||
TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or
|
||||
TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) {
|
||||
Language::hasOpaqueType(tag, byteSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* The language-neutral type of an IR `Instruction`, `Operand`, or `IRVariable`.
|
||||
* The interface to `IRType` and its subclasses is the same across all languages for which the IR
|
||||
* is supported, so analyses that expect to be used for multiple languages should generally use
|
||||
* `IRType` rather than a language-specific type.
|
||||
*
|
||||
* Many types from the language-specific type system will map to a single canonical `IRType`. Two
|
||||
* types that map to the same `IRType` are considered equivalent by the IR. As an example, in C++,
|
||||
* all pointer types map to the same instance of `IRAddressType`.
|
||||
*/
|
||||
class IRType extends TIRType {
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a string that uniquely identifies this `IRType`. This string is often the same as the
|
||||
* result of `IRType.toString()`, but for some types it may be more verbose to ensure uniqueness.
|
||||
*/
|
||||
string getIdentityString() { result = toString() }
|
||||
|
||||
/**
|
||||
* Gets the size of the type, in bytes, if known.
|
||||
*
|
||||
* This will hold for all `IRType` objects except `IRUnknownType`.
|
||||
*/
|
||||
int getByteSize() { none() }
|
||||
|
||||
/**
|
||||
* Gets a single instance of `LanguageType` that maps to this `IRType`.
|
||||
*/
|
||||
Language::LanguageType getCanonicalLanguageType() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unknown type. Generally used to represent results and operands that access an unknown set of
|
||||
* memory locations, such as the side effects of a function call.
|
||||
*/
|
||||
class IRUnknownType extends IRType, TIRUnknownType {
|
||||
final override string toString() { result = "unknown" }
|
||||
|
||||
final override int getByteSize() { none() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalUnknownType()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A void type, which has no values. Used to represent the result type of an instruction that does
|
||||
* not produce a result.
|
||||
*/
|
||||
class IRVoidType extends IRType, TIRVoidType {
|
||||
final override string toString() { result = "void" }
|
||||
|
||||
final override int getByteSize() { result = 0 }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalVoidType()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error type. Used when an error in the source code prevents the extractor from determining the
|
||||
* proper type.
|
||||
*/
|
||||
class IRErrorType extends IRType, TIRErrorType {
|
||||
final override string toString() { result = "error" }
|
||||
|
||||
final override int getByteSize() { result = 0 }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalErrorType()
|
||||
}
|
||||
}
|
||||
|
||||
private class IRSizedType extends IRType {
|
||||
int byteSize;
|
||||
|
||||
IRSizedType() {
|
||||
this = TIRBooleanType(byteSize) or
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize) or
|
||||
this = TIRAddressType(byteSize) or
|
||||
this = TIRFunctionAddressType(byteSize) or
|
||||
this = TIROpaqueType(_, byteSize)
|
||||
}
|
||||
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Boolean type, which can hold the values `true` (non-zero) or `false` (zero).
|
||||
*/
|
||||
class IRBooleanType extends IRSizedType, TIRBooleanType {
|
||||
final override string toString() { result = "bool" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalBooleanType(byteSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
|
||||
* `IRFloatingPointType`.
|
||||
*/
|
||||
class IRNumericType extends IRSizedType {
|
||||
IRNumericType() {
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
|
||||
* integer, as well as character types whose representation is signed.
|
||||
*/
|
||||
class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
|
||||
final override string toString() { result = "int" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalSignedIntegerType(byteSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
|
||||
* unsigned integer, as well as character types whose representation is unsigned.
|
||||
*/
|
||||
class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
|
||||
final override string toString() { result = "uint" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalUnsignedIntegerType(byteSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A floating-point type.
|
||||
*/
|
||||
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
|
||||
final override string toString() { result = "float" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalFloatingPointType(byteSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An address type, representing the memory address of data. Used to represent pointers, references,
|
||||
* and lvalues, include those that are garbage collected.
|
||||
*
|
||||
* The address of a function is represented by the separate `IRFunctionAddressType`.
|
||||
*/
|
||||
class IRAddressType extends IRSizedType, TIRAddressType {
|
||||
final override string toString() { result = "addr" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalAddressType(byteSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An address type, representing the memory address of code. Used to represent function pointers,
|
||||
* function references, and the target of a direct function call.
|
||||
*/
|
||||
class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType {
|
||||
final override string toString() { result = "func" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalFunctionAddressType(byteSize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type with known size that does not fit any of the other kinds of type. Used to represent
|
||||
* classes, structs, unions, fixed-size arrays, pointers-to-member, and more.
|
||||
*/
|
||||
class IROpaqueType extends IRSizedType, TIROpaqueType {
|
||||
Language::OpaqueTypeTag tag;
|
||||
|
||||
IROpaqueType() { this = TIROpaqueType(tag, byteSize) }
|
||||
|
||||
final override string toString() {
|
||||
result = "opaque" + byteSize.toString() + "{" + tag.toString() + "}"
|
||||
}
|
||||
|
||||
final override string getIdentityString() {
|
||||
result = "opaque" + byteSize.toString() + "{" + Language::getOpaqueTagIdentityString(tag) + "}"
|
||||
}
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalOpaqueType(tag, byteSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "tag" that differentiates this type from other incompatible opaque types that have the
|
||||
* same size.
|
||||
*/
|
||||
final Language::OpaqueTypeTag getTag() { result = tag }
|
||||
}
|
||||
|
||||
module IRTypeSanity {
|
||||
query predicate missingCanonicalLanguageType(IRType type, string message) {
|
||||
not exists(type.getCanonicalLanguageType()) and
|
||||
message = "Type does not have a canonical `LanguageType`"
|
||||
}
|
||||
|
||||
query predicate multipleCanonicalLanguageTypes(IRType type, string message) {
|
||||
strictcount(type.getCanonicalLanguageType()) > 1 and
|
||||
message = "Type has multiple canonical `LanguageType`s: " +
|
||||
concat(type.getCanonicalLanguageType().toString(), ", ")
|
||||
}
|
||||
|
||||
query predicate missingIRType(Language::LanguageType type, string message) {
|
||||
not exists(type.getIRType()) and
|
||||
message = "`LanguageType` does not have a corresponding `IRType`."
|
||||
}
|
||||
|
||||
query predicate multipleIRTypes(Language::LanguageType type, string message) {
|
||||
strictcount(type.getIRType()) > 1 and
|
||||
message = "`LanguageType` " + type.getAQlClass() + " has multiple `IRType`s: " +
|
||||
concat(type.getIRType().toString(), ", ")
|
||||
}
|
||||
|
||||
import Language::LanguageTypeSanity
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import IRVariable
|
||||
import Operand
|
||||
private import internal.IRImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::IRType
|
||||
import Imports::MemoryAccessKind
|
||||
|
||||
private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
|
||||
@@ -5,6 +5,7 @@ import Imports::TempVariableTag
|
||||
private import Imports::IRUtilities
|
||||
private import Imports::TTempVariableTag
|
||||
private import Imports::TIRVariable
|
||||
private import Imports::IRType
|
||||
|
||||
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
|
||||
result.getVariable() = var and
|
||||
@@ -24,7 +25,17 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::Type getType();
|
||||
final Language::Type getType() { getLanguageType().hasType(result, false) }
|
||||
|
||||
/**
|
||||
* Gets the language-neutral type of the variable.
|
||||
*/
|
||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
@@ -59,7 +70,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::Type type;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRUserVariable() { this = TIRUserVariable(var, type, func) }
|
||||
|
||||
@@ -71,7 +82,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
}
|
||||
|
||||
final override Language::Type getType() { result = type }
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
@@ -110,11 +121,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Language::AST ast;
|
||||
TempVariableTag tag;
|
||||
Language::Type type;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
|
||||
final override Language::Type getType() { result = type }
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRVariable
|
||||
import Operand
|
||||
private import internal.InstructionImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::IRType
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
@@ -113,10 +114,12 @@ module InstructionSanity {
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func |
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
func = operand.getUse().getEnclosingFunction() and
|
||||
message = "Operand missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString()
|
||||
+ "' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -321,7 +324,7 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if getResultType() instanceof Language::VoidType
|
||||
if getResultIRType() instanceof IRVoidType
|
||||
then result = "v"
|
||||
else
|
||||
if hasMemoryResult()
|
||||
@@ -353,23 +356,6 @@ class Instruction extends Construction::TInstruction {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isGLValue() then result = "glval<" + type + ">" else result = type
|
||||
}
|
||||
|
||||
string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if
|
||||
getResultType() instanceof Language::UnknownType and
|
||||
not isGLValue() and
|
||||
exists(getResultSize())
|
||||
then result = valcat + "[" + getResultSize().toString() + "]"
|
||||
else result = valcat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -389,7 +375,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*
|
||||
* Example: `r1_1(int*)`
|
||||
*/
|
||||
final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" }
|
||||
final string getResultString() {
|
||||
result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
@@ -457,6 +445,16 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
final Language::LanguageType getResultLanguageType() {
|
||||
result = Construction::getInstructionResultType(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
* instruction does not produce a result, its result type will be `VoidType`.
|
||||
@@ -464,7 +462,16 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `isGLValue()` holds, then the result type of this instruction should be
|
||||
* thought of as "pointer to `getResultType()`".
|
||||
*/
|
||||
final Language::Type getResultType() { Construction::instructionHasType(this, result, _) }
|
||||
final Language::Type getResultType() {
|
||||
exists(Language::LanguageType resultType |
|
||||
resultType = getResultLanguageType() and
|
||||
(
|
||||
resultType.hasUnspecifiedType(result, _)
|
||||
or
|
||||
not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the result produced by this instruction is a glvalue. If this
|
||||
@@ -484,7 +491,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isGLValue() { Construction::instructionHasType(this, _, true) }
|
||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
@@ -493,16 +500,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
final int getResultSize() {
|
||||
if isGLValue()
|
||||
then
|
||||
// a glvalue is always pointer-sized.
|
||||
result = Language::getPointerSize()
|
||||
else
|
||||
if getResultType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionResultSize(this)
|
||||
else result = Language::getTypeSize(getResultType())
|
||||
}
|
||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
||||
|
||||
/**
|
||||
* Gets the opcode that specifies the operation performed by this instruction.
|
||||
@@ -1384,7 +1382,7 @@ class CatchInstruction extends Instruction {
|
||||
* An instruction that catches an exception of a specific type.
|
||||
*/
|
||||
class CatchByTypeInstruction extends CatchInstruction {
|
||||
Language::Type exceptionType;
|
||||
Language::LanguageType exceptionType;
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
@@ -1396,7 +1394,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
/**
|
||||
* Gets the type of exception to be caught.
|
||||
*/
|
||||
final Language::Type getExceptionType() { result = exceptionType }
|
||||
final Language::LanguageType getExceptionType() { result = exceptionType }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
private import Instruction
|
||||
private import IRBlock
|
||||
private import internal.OperandImports as Imports
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Overlap
|
||||
private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
@@ -143,22 +144,40 @@ class Operand extends TOperand {
|
||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
Language::Type getType() { result = getAnyDef().getResultType() }
|
||||
Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
|
||||
|
||||
/**
|
||||
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
||||
* as the result type of the definition instruction consumed by this operand. For register
|
||||
* operands, this is always the case. For some memory operands, the operand type may be different
|
||||
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||
* result type of the definition instruction consumed by this operand. For register operands,
|
||||
* this is always the case. For some memory operands, the operand type may be different from
|
||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
final Language::Type getType() { getLanguageType().hasType(result, _) }
|
||||
|
||||
/**
|
||||
* Holds if the value consumed by this operand is a glvalue. If this
|
||||
* holds, the value of the operand represents the address of a location,
|
||||
* and the type of the location is given by `getType()`. If this does
|
||||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
* given by `getType()`.
|
||||
*/
|
||||
predicate isGLValue() { getAnyDef().isGLValue() }
|
||||
final predicate isGLValue() { getLanguageType().hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() { result = Language::getTypeSize(getType()) }
|
||||
final int getSize() { result = getLanguageType().getByteSize() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,11 +189,6 @@ class MemoryOperand extends Operand {
|
||||
this = TPhiOperand(_, _, _, _)
|
||||
}
|
||||
|
||||
override predicate isGLValue() {
|
||||
// A `MemoryOperand` can never be a glvalue
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the operand.
|
||||
*/
|
||||
@@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
class TypedOperand extends NonPhiMemoryOperand {
|
||||
override TypedOperandTag tag;
|
||||
|
||||
final override Language::Type getType() {
|
||||
final override Language::LanguageType getLanguageType() {
|
||||
result = Construction::getInstructionOperandType(useInstr, tag)
|
||||
}
|
||||
}
|
||||
@@ -381,12 +395,6 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
final override int getSize() {
|
||||
if getType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
useInstr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
private import cpp
|
||||
private import internal.ValueNumberingImports
|
||||
private import IR
|
||||
|
||||
/**
|
||||
@@ -23,31 +23,32 @@ newtype TValueNumber =
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, Type type, string value) {
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, Type type, string value) {
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, ValueNumber objectAddress) {
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand) {
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
ValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
@@ -59,7 +60,7 @@ newtype TValueNumber =
|
||||
class ValueNumber extends TValueNumber {
|
||||
final string toString() { result = getExampleInstruction().getResultId() }
|
||||
|
||||
final Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
@@ -150,23 +151,23 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, Type type, string value
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, Type type, string value
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Field field, ValueNumber objectAddress
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
@@ -174,43 +175,43 @@ private predicate fieldAddressValueNumber(
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, Type type, int elementSize,
|
||||
ValueNumber leftOperand, ValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, Class baseClass,
|
||||
Class derivedClass, ValueNumber operand
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
@@ -225,7 +226,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultType() instanceof VoidType and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
@@ -269,38 +270,41 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(Type type, string value |
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Type type, string value |
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Field field, ValueNumber objectAddress |
|
||||
exists(Language::Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Type type, ValueNumber operand |
|
||||
exists(Opcode opcode, IRType type, ValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand |
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
@@ -1,6 +1,6 @@
|
||||
private import cpp
|
||||
import AliasAnalysis
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
private import semmle.code.cpp.Print
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
@@ -10,29 +10,39 @@ private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
private predicate hasResultMemoryAccess(
|
||||
Instruction instr, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset
|
||||
Instruction instr, IRVariable var, IRType type, Language::LanguageType languageType,
|
||||
IntValue startBitOffset, IntValue endBitOffset
|
||||
) {
|
||||
resultPointsTo(instr.getResultAddress(), var, startBitOffset) and
|
||||
type = instr.getResultType() and
|
||||
if exists(instr.getResultSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(instr.getResultSize(), 8))
|
||||
languageType = instr.getResultLanguageType() and
|
||||
type = languageType.getIRType() and
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
}
|
||||
|
||||
private predicate hasOperandMemoryAccess(
|
||||
MemoryOperand operand, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset
|
||||
MemoryOperand operand, IRVariable var, IRType type, Language::LanguageType languageType,
|
||||
IntValue startBitOffset, IntValue endBitOffset
|
||||
) {
|
||||
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, startBitOffset) and
|
||||
type = operand.getType() and
|
||||
if exists(operand.getSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(operand.getSize(), 8))
|
||||
languageType = operand.getLanguageType() and
|
||||
type = languageType.getIRType() and
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
}
|
||||
|
||||
private newtype TMemoryLocation =
|
||||
TVariableMemoryLocation(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset) {
|
||||
hasResultMemoryAccess(_, var, type, startBitOffset, endBitOffset) or
|
||||
hasOperandMemoryAccess(_, var, type, startBitOffset, endBitOffset)
|
||||
TVariableMemoryLocation(
|
||||
IRVariable var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
|
||||
IntValue endBitOffset
|
||||
) {
|
||||
(
|
||||
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset) or
|
||||
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset)
|
||||
) and
|
||||
languageType = type.getCanonicalLanguageType()
|
||||
} or
|
||||
TUnknownMemoryLocation(IRFunction irFunc) or
|
||||
TUnknownVirtualVariable(IRFunction irFunc)
|
||||
@@ -49,9 +59,11 @@ abstract class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
abstract VirtualVariable getVirtualVariable();
|
||||
|
||||
abstract Type getType();
|
||||
abstract Language::LanguageType getType();
|
||||
|
||||
abstract string getUniqueId();
|
||||
|
||||
final IRType getIRType() { result = getType().getIRType() }
|
||||
}
|
||||
|
||||
abstract class VirtualVariable extends MemoryLocation { }
|
||||
@@ -62,20 +74,34 @@ abstract class VirtualVariable extends MemoryLocation { }
|
||||
*/
|
||||
class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
|
||||
IRVariable var;
|
||||
Type type;
|
||||
IRType type;
|
||||
Language::LanguageType languageType;
|
||||
IntValue startBitOffset;
|
||||
IntValue endBitOffset;
|
||||
|
||||
VariableMemoryLocation() {
|
||||
this = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset)
|
||||
this = TVariableMemoryLocation(var, type, languageType, startBitOffset, endBitOffset)
|
||||
}
|
||||
|
||||
final override string toString() {
|
||||
result = var.toString() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
|
||||
type.toString() + ">"
|
||||
type.toString() + ", " + languageType.toString() + ">"
|
||||
}
|
||||
|
||||
final override Type getType() { result = type }
|
||||
final override Language::LanguageType getType() {
|
||||
if
|
||||
strictcount(Language::LanguageType accessType |
|
||||
hasResultMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset) or
|
||||
hasOperandMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset)
|
||||
) = 1
|
||||
then
|
||||
// All of the accesses have the same `LanguageType`, so just use that.
|
||||
hasResultMemoryAccess(_, var, type, result, startBitOffset, endBitOffset) or
|
||||
hasOperandMemoryAccess(_, var, type, result, startBitOffset, endBitOffset)
|
||||
else
|
||||
// There is no single type for all accesses, so just use the canonical one for this `IRType`.
|
||||
result = type.getCanonicalLanguageType()
|
||||
}
|
||||
|
||||
final IntValue getStartBitOffset() { result = startBitOffset }
|
||||
|
||||
@@ -85,13 +111,14 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
|
||||
|
||||
final override string getUniqueId() {
|
||||
result = var.getUniqueId() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
|
||||
getTypeIdentityString(type) + ">"
|
||||
type.getIdentityString() + ">"
|
||||
}
|
||||
|
||||
final override VirtualVariable getVirtualVariable() {
|
||||
if variableAddressEscapes(var)
|
||||
then result = TUnknownVirtualVariable(var.getEnclosingIRFunction())
|
||||
else result = TVariableMemoryLocation(var, var.getType(), 0, var.getType().getSize() * 8)
|
||||
else
|
||||
result = TVariableMemoryLocation(var, var.getIRType(), _, 0, var.getIRType().getByteSize() * 8)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +126,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
|
||||
*/
|
||||
final predicate coversEntireVariable() {
|
||||
startBitOffset = 0 and
|
||||
endBitOffset = var.getType().getSize() * 8
|
||||
endBitOffset = var.getIRType().getByteSize() * 8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +138,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
|
||||
class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable {
|
||||
VariableVirtualVariable() {
|
||||
not variableAddressEscapes(var) and
|
||||
type = var.getType() and
|
||||
type = var.getIRType() and
|
||||
coversEntireVariable()
|
||||
}
|
||||
}
|
||||
@@ -128,7 +155,9 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
|
||||
|
||||
final override VirtualVariable getVirtualVariable() { result = TUnknownVirtualVariable(irFunc) }
|
||||
|
||||
final override Type getType() { result instanceof UnknownType }
|
||||
final override Language::LanguageType getType() {
|
||||
result = any(IRUnknownType type).getCanonicalLanguageType()
|
||||
}
|
||||
|
||||
final override string getUniqueId() { result = "{Unknown}" }
|
||||
}
|
||||
@@ -143,7 +172,9 @@ class UnknownVirtualVariable extends TUnknownVirtualVariable, VirtualVariable {
|
||||
|
||||
final override string toString() { result = "{AllAliased}" }
|
||||
|
||||
final override Type getType() { result instanceof UnknownType }
|
||||
final override Language::LanguageType getType() {
|
||||
result = any(IRUnknownType type).getCanonicalLanguageType()
|
||||
}
|
||||
|
||||
final override string getUniqueId() { result = " " + toString() }
|
||||
|
||||
@@ -177,7 +208,7 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
intervalOverlap = getVariableMemoryLocationOverlap(def, use) and
|
||||
if intervalOverlap instanceof MustExactlyOverlap
|
||||
then
|
||||
if def.getType() = use.getType()
|
||||
if def.getIRType() = use.getIRType()
|
||||
then
|
||||
// The def and use types match, so it's an exact overlap.
|
||||
result instanceof MustExactlyOverlap
|
||||
@@ -282,11 +313,11 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
(
|
||||
(
|
||||
kind.usesAddressOperand() and
|
||||
if hasResultMemoryAccess(instr, _, _, _, _)
|
||||
if hasResultMemoryAccess(instr, _, _, _, _, _)
|
||||
then
|
||||
exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset |
|
||||
hasResultMemoryAccess(instr, var, type, startBitOffset, endBitOffset) and
|
||||
result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset)
|
||||
exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
|
||||
hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset) and
|
||||
result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset)
|
||||
)
|
||||
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction())
|
||||
)
|
||||
@@ -306,11 +337,11 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
(
|
||||
(
|
||||
kind.usesAddressOperand() and
|
||||
if hasOperandMemoryAccess(operand, _, _, _, _)
|
||||
if hasOperandMemoryAccess(operand, _, _, _, _, _)
|
||||
then
|
||||
exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset |
|
||||
hasOperandMemoryAccess(operand, var, type, startBitOffset, endBitOffset) and
|
||||
result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset)
|
||||
exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
|
||||
hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset) and
|
||||
result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset)
|
||||
)
|
||||
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction())
|
||||
)
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag
|
||||
import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities
|
||||
import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
|
||||
@@ -4,34 +4,52 @@ private import Alias
|
||||
private import SSAConstruction
|
||||
private import DebugSSA
|
||||
|
||||
bindingset[offset]
|
||||
private string getKeySuffixForOffset(int offset) {
|
||||
if offset % 2 = 0 then result = "" else result = "_Chi"
|
||||
}
|
||||
|
||||
bindingset[offset]
|
||||
private int getIndexForOffset(int offset) { result = offset / 2 }
|
||||
|
||||
/**
|
||||
* Property provide that dumps the memory access of each result. Useful for debugging SSA
|
||||
* construction.
|
||||
*/
|
||||
class PropertyProvider extends IRPropertyProvider {
|
||||
override string getInstructionProperty(Instruction instruction, string key) {
|
||||
exists(MemoryLocation location |
|
||||
location = getResultMemoryLocation(instruction) and
|
||||
(
|
||||
key = "ResultMemoryLocation" and result = location.toString()
|
||||
or
|
||||
key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString()
|
||||
key = "ResultMemoryLocation" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getResultMemoryLocation(instruction)
|
||||
|
|
||||
loc.toString(), ","
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation location |
|
||||
location = getOperandMemoryLocation(instruction.getAnOperand()) and
|
||||
(
|
||||
key = "OperandMemoryAccess" and result = location.toString()
|
||||
or
|
||||
key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString()
|
||||
key = "ResultVirtualVariable" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getResultMemoryLocation(instruction)
|
||||
|
|
||||
loc.getVirtualVariable().toString(), ","
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
|
||||
defBlock.getInstruction(defIndex) = instruction and
|
||||
key = "DefinitionRank[" + useLocation.toString() + "]" and
|
||||
key = "OperandMemoryLocation" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getOperandMemoryLocation(instruction.getAnOperand())
|
||||
|
|
||||
loc.toString(), ","
|
||||
)
|
||||
or
|
||||
key = "OperandVirtualVariable" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getOperandMemoryLocation(instruction.getAnOperand())
|
||||
|
|
||||
loc.getVirtualVariable().toString(), ","
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
|
||||
defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
|
||||
key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and
|
||||
result = defRank.toString()
|
||||
)
|
||||
or
|
||||
@@ -41,10 +59,11 @@ class PropertyProvider extends IRPropertyProvider {
|
||||
result = useRank.toString()
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
|
||||
defBlock.getInstruction(defIndex) = instruction and
|
||||
key = "DefinitionReachesUse[" + useLocation.toString() + "]" and
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
|
||||
defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
|
||||
key = "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString()
|
||||
+ "]" and
|
||||
result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
|
||||
exists(Instruction useInstruction |
|
||||
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import SSAConstructionInternal
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
private import SSAConstructionImports
|
||||
private import NewIR
|
||||
|
||||
private class OldBlock = Reachability::ReachableBlock;
|
||||
@@ -18,7 +15,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate functionHasIR(Function func) {
|
||||
predicate functionHasIR(Language::Function func) {
|
||||
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
|
||||
}
|
||||
|
||||
@@ -42,7 +39,7 @@ private module Cached {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
||||
hasChiNode(_, oldInstruction)
|
||||
} or
|
||||
Unreached(Function function) {
|
||||
Unreached(Language::Function function) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
function = oldInstruction.getEnclosingFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
@@ -50,12 +47,14 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
|
||||
predicate hasTempVariable(
|
||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
||||
) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getEnclosingFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getType() = type
|
||||
var.getLanguageType() = type
|
||||
)
|
||||
}
|
||||
|
||||
@@ -135,24 +134,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
|
||||
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instr) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
result = oldOperand.getType()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instr) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
// Only return a result for operands that need an explicit result size.
|
||||
oldOperand.getType() instanceof UnknownType and
|
||||
result = oldOperand.getSize()
|
||||
result = oldOperand.getLanguageType()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -196,20 +183,21 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
* the new instructions generated from the successors of the old instruction
|
||||
*/
|
||||
|
||||
cached
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
if hasChiNode(_, getOldInstruction(instruction))
|
||||
@@ -252,7 +240,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Locatable getInstructionAST(Instruction instruction) {
|
||||
Language::AST getInstructionAST(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction)
|
||||
or
|
||||
@@ -270,29 +258,25 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
|
||||
Language::LanguageType getInstructionResultType(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction) and
|
||||
type = oldInstruction.getResultType() and
|
||||
if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false
|
||||
result = oldInstruction.getResultLanguageType()
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
||||
instruction = Chi(oldInstruction) and
|
||||
hasChiNode(vvar, oldInstruction) and
|
||||
type = vvar.getType() and
|
||||
isGLValue = false
|
||||
result = vvar.getType()
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = Phi(_, location) and
|
||||
type = location.getType() and
|
||||
isGLValue = false
|
||||
result = location.getType()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(_) and
|
||||
type instanceof VoidType and
|
||||
isGLValue = false
|
||||
result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -338,7 +322,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Field getInstructionField(Instruction instruction) {
|
||||
Language::Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
@@ -348,7 +332,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Function getInstructionFunction(Instruction instruction) {
|
||||
Language::Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
@@ -358,19 +342,19 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
|
||||
}
|
||||
|
||||
cached
|
||||
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
|
||||
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
|
||||
result = getOldInstruction(instruction)
|
||||
.(OldIR::BuiltInOperationInstruction)
|
||||
.getBuiltInOperation()
|
||||
}
|
||||
|
||||
cached
|
||||
Type getInstructionExceptionType(Instruction instruction) {
|
||||
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
@@ -380,14 +364,9 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionResultSize(Instruction instruction) {
|
||||
// Only return a result for instructions that needed an explicit result size.
|
||||
instruction.getResultType() instanceof UnknownType and
|
||||
result = getOldInstruction(instruction).getResultSize()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
|
||||
predicate getInstructionInheritance(
|
||||
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
|
||||
) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
@@ -2,4 +2,5 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import AliasedSSA as Alias
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
@@ -2,11 +2,11 @@ private import TIRVariableInternal
|
||||
private import Imports::TempVariableTag
|
||||
|
||||
newtype TIRVariable =
|
||||
TIRUserVariable(Language::Variable var, Language::Type type, Language::Function func) {
|
||||
TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Function func) {
|
||||
Construction::hasUserVariable(func, var, type)
|
||||
} or
|
||||
TIRTempVariable(
|
||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type
|
||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
||||
) {
|
||||
Construction::hasTempVariable(func, ast, tag, type)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRVariable
|
||||
import Operand
|
||||
private import internal.IRImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::IRType
|
||||
import Imports::MemoryAccessKind
|
||||
|
||||
private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
|
||||
@@ -5,6 +5,7 @@ import Imports::TempVariableTag
|
||||
private import Imports::IRUtilities
|
||||
private import Imports::TTempVariableTag
|
||||
private import Imports::TIRVariable
|
||||
private import Imports::IRType
|
||||
|
||||
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
|
||||
result.getVariable() = var and
|
||||
@@ -24,7 +25,17 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::Type getType();
|
||||
final Language::Type getType() { getLanguageType().hasType(result, false) }
|
||||
|
||||
/**
|
||||
* Gets the language-neutral type of the variable.
|
||||
*/
|
||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
@@ -59,7 +70,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::Type type;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRUserVariable() { this = TIRUserVariable(var, type, func) }
|
||||
|
||||
@@ -71,7 +82,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
}
|
||||
|
||||
final override Language::Type getType() { result = type }
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
@@ -110,11 +121,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Language::AST ast;
|
||||
TempVariableTag tag;
|
||||
Language::Type type;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
|
||||
final override Language::Type getType() { result = type }
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRVariable
|
||||
import Operand
|
||||
private import internal.InstructionImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::IRType
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
@@ -113,10 +114,12 @@ module InstructionSanity {
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func |
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
func = operand.getUse().getEnclosingFunction() and
|
||||
message = "Operand missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString()
|
||||
+ "' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -321,7 +324,7 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if getResultType() instanceof Language::VoidType
|
||||
if getResultIRType() instanceof IRVoidType
|
||||
then result = "v"
|
||||
else
|
||||
if hasMemoryResult()
|
||||
@@ -353,23 +356,6 @@ class Instruction extends Construction::TInstruction {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isGLValue() then result = "glval<" + type + ">" else result = type
|
||||
}
|
||||
|
||||
string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if
|
||||
getResultType() instanceof Language::UnknownType and
|
||||
not isGLValue() and
|
||||
exists(getResultSize())
|
||||
then result = valcat + "[" + getResultSize().toString() + "]"
|
||||
else result = valcat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -389,7 +375,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*
|
||||
* Example: `r1_1(int*)`
|
||||
*/
|
||||
final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" }
|
||||
final string getResultString() {
|
||||
result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
@@ -457,6 +445,16 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
final Language::LanguageType getResultLanguageType() {
|
||||
result = Construction::getInstructionResultType(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
* instruction does not produce a result, its result type will be `VoidType`.
|
||||
@@ -464,7 +462,16 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `isGLValue()` holds, then the result type of this instruction should be
|
||||
* thought of as "pointer to `getResultType()`".
|
||||
*/
|
||||
final Language::Type getResultType() { Construction::instructionHasType(this, result, _) }
|
||||
final Language::Type getResultType() {
|
||||
exists(Language::LanguageType resultType |
|
||||
resultType = getResultLanguageType() and
|
||||
(
|
||||
resultType.hasUnspecifiedType(result, _)
|
||||
or
|
||||
not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the result produced by this instruction is a glvalue. If this
|
||||
@@ -484,7 +491,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isGLValue() { Construction::instructionHasType(this, _, true) }
|
||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
@@ -493,16 +500,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
final int getResultSize() {
|
||||
if isGLValue()
|
||||
then
|
||||
// a glvalue is always pointer-sized.
|
||||
result = Language::getPointerSize()
|
||||
else
|
||||
if getResultType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionResultSize(this)
|
||||
else result = Language::getTypeSize(getResultType())
|
||||
}
|
||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
||||
|
||||
/**
|
||||
* Gets the opcode that specifies the operation performed by this instruction.
|
||||
@@ -1384,7 +1382,7 @@ class CatchInstruction extends Instruction {
|
||||
* An instruction that catches an exception of a specific type.
|
||||
*/
|
||||
class CatchByTypeInstruction extends CatchInstruction {
|
||||
Language::Type exceptionType;
|
||||
Language::LanguageType exceptionType;
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
@@ -1396,7 +1394,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
/**
|
||||
* Gets the type of exception to be caught.
|
||||
*/
|
||||
final Language::Type getExceptionType() { result = exceptionType }
|
||||
final Language::LanguageType getExceptionType() { result = exceptionType }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
private import Instruction
|
||||
private import IRBlock
|
||||
private import internal.OperandImports as Imports
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Overlap
|
||||
private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
@@ -143,22 +144,40 @@ class Operand extends TOperand {
|
||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
Language::Type getType() { result = getAnyDef().getResultType() }
|
||||
Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
|
||||
|
||||
/**
|
||||
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
||||
* as the result type of the definition instruction consumed by this operand. For register
|
||||
* operands, this is always the case. For some memory operands, the operand type may be different
|
||||
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||
* result type of the definition instruction consumed by this operand. For register operands,
|
||||
* this is always the case. For some memory operands, the operand type may be different from
|
||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
final Language::Type getType() { getLanguageType().hasType(result, _) }
|
||||
|
||||
/**
|
||||
* Holds if the value consumed by this operand is a glvalue. If this
|
||||
* holds, the value of the operand represents the address of a location,
|
||||
* and the type of the location is given by `getType()`. If this does
|
||||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
* given by `getType()`.
|
||||
*/
|
||||
predicate isGLValue() { getAnyDef().isGLValue() }
|
||||
final predicate isGLValue() { getLanguageType().hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() { result = Language::getTypeSize(getType()) }
|
||||
final int getSize() { result = getLanguageType().getByteSize() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,11 +189,6 @@ class MemoryOperand extends Operand {
|
||||
this = TPhiOperand(_, _, _, _)
|
||||
}
|
||||
|
||||
override predicate isGLValue() {
|
||||
// A `MemoryOperand` can never be a glvalue
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the operand.
|
||||
*/
|
||||
@@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
class TypedOperand extends NonPhiMemoryOperand {
|
||||
override TypedOperandTag tag;
|
||||
|
||||
final override Language::Type getType() {
|
||||
final override Language::LanguageType getLanguageType() {
|
||||
result = Construction::getInstructionOperandType(useInstr, tag)
|
||||
}
|
||||
}
|
||||
@@ -381,12 +395,6 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
final override int getSize() {
|
||||
if getType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
useInstr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
private import cpp
|
||||
private import internal.ValueNumberingImports
|
||||
private import IR
|
||||
|
||||
/**
|
||||
@@ -23,31 +23,32 @@ newtype TValueNumber =
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, Type type, string value) {
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, Type type, string value) {
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, ValueNumber objectAddress) {
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand) {
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
ValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
@@ -59,7 +60,7 @@ newtype TValueNumber =
|
||||
class ValueNumber extends TValueNumber {
|
||||
final string toString() { result = getExampleInstruction().getResultId() }
|
||||
|
||||
final Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
@@ -150,23 +151,23 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, Type type, string value
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, Type type, string value
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Field field, ValueNumber objectAddress
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
@@ -174,43 +175,43 @@ private predicate fieldAddressValueNumber(
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, Type type, int elementSize,
|
||||
ValueNumber leftOperand, ValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, Class baseClass,
|
||||
Class derivedClass, ValueNumber operand
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
@@ -225,7 +226,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultType() instanceof VoidType and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
@@ -269,38 +270,41 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(Type type, string value |
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Type type, string value |
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Field field, ValueNumber objectAddress |
|
||||
exists(Language::Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Type type, ValueNumber operand |
|
||||
exists(Opcode opcode, IRType type, ValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand |
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
@@ -1,6 +1,8 @@
|
||||
private import cpp
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
@@ -25,16 +27,16 @@ private module Cached {
|
||||
cached
|
||||
newtype TInstruction =
|
||||
MkInstruction(TranslatedElement element, InstructionTag tag) {
|
||||
element.hasInstruction(_, tag, _, _)
|
||||
element.hasInstruction(_, tag, _)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasUserVariable(Function func, Variable var, Type type) {
|
||||
predicate hasUserVariable(Function func, Variable var, CppType type) {
|
||||
getTranslatedFunction(func).hasUserVariable(var, type)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
|
||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
|
||||
exists(TranslatedElement element |
|
||||
element.getAST() = ast and
|
||||
func = element.getFunction() and
|
||||
@@ -82,22 +84,16 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Type 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
|
||||
// the result type of the load.
|
||||
result = instruction.(LoadInstruction).getResultType()
|
||||
result = instruction.(LoadInstruction).getResultLanguageType()
|
||||
or
|
||||
not instruction instanceof LoadInstruction and
|
||||
result = getInstructionTranslatedElement(instruction)
|
||||
.getInstructionOperandType(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionOperandSize(Instruction instruction, SideEffectOperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction)
|
||||
.getInstructionOperandSize(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getPhiOperandDefinition(
|
||||
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
|
||||
@@ -217,15 +213,15 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
|
||||
CppType getInstructionResultType(Instruction instruction) {
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.hasInstruction(_, getInstructionTag(instruction), type, isGLValue)
|
||||
.hasInstruction(_, getInstructionTag(instruction), result)
|
||||
}
|
||||
|
||||
cached
|
||||
Opcode getInstructionOpcode(Instruction instruction) {
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.hasInstruction(result, getInstructionTag(instruction), _, _)
|
||||
.hasInstruction(result, getInstructionTag(instruction), _)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -280,7 +276,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Type getInstructionExceptionType(Instruction instruction) {
|
||||
CppType getInstructionExceptionType(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction)
|
||||
.getInstructionExceptionType(getInstructionTag(instruction))
|
||||
}
|
||||
@@ -307,6 +303,11 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate needsUnknownOpaqueType(int byteSize) {
|
||||
exists(TranslatedElement element | element.needsUnknownOpaqueType(byteSize))
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionResultSize(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag
|
||||
import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities
|
||||
import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
@@ -33,13 +34,10 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
else result = getFirstCallTargetInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = CallTag() and
|
||||
opcode instanceof Opcode::Call and
|
||||
resultType = getCallResultType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(getCallResultType())
|
||||
or
|
||||
hasSideEffect() and
|
||||
tag = CallSideEffectTag() and
|
||||
@@ -47,13 +45,12 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
if hasWriteSideEffect()
|
||||
then (
|
||||
opcode instanceof Opcode::CallSideEffect and
|
||||
resultType instanceof UnknownType
|
||||
resultType = getUnknownType()
|
||||
) else (
|
||||
opcode instanceof Opcode::CallReadSideEffect and
|
||||
resultType instanceof VoidType
|
||||
resultType = getVoidType()
|
||||
)
|
||||
) and
|
||||
isGLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
@@ -118,11 +115,11 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
}
|
||||
|
||||
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
tag = CallSideEffectTag() and
|
||||
hasSideEffect() and
|
||||
operandTag instanceof SideEffectOperandTag and
|
||||
result instanceof UnknownType
|
||||
result = getUnknownType()
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = getInstruction(CallTag()) }
|
||||
@@ -224,18 +221,12 @@ abstract class TranslatedDirectCall extends TranslatedCall {
|
||||
|
||||
final override Instruction getCallTargetResult() { result = getInstruction(CallTargetTag()) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
TranslatedCall.super.hasInstruction(opcode, tag, resultType, isGLValue)
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedCall.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = CallTargetTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
// The database does not contain a `FunctionType` for a function unless
|
||||
// its address was taken, so we'll just use glval<Unknown> instead of
|
||||
// glval<FunctionType>.
|
||||
resultType instanceof UnknownType and
|
||||
isGLValue = true
|
||||
resultType = getFunctionGLValueType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -253,7 +244,7 @@ abstract class TranslatedDirectCall extends TranslatedCall {
|
||||
abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedCall {
|
||||
override Call expr;
|
||||
|
||||
final override Type getCallResultType() { result = getResultType() }
|
||||
final override Type getCallResultType() { result = expr.getType() }
|
||||
|
||||
final override predicate hasArguments() { exists(expr.getArgument(0)) }
|
||||
|
||||
@@ -349,9 +340,7 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) {
|
||||
none()
|
||||
}
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() }
|
||||
|
||||
@@ -359,7 +348,9 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
|
||||
|
||||
override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() }
|
||||
override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedFunction` containing this expression.
|
||||
@@ -406,34 +397,30 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
|
||||
isWrite() and
|
||||
hasSpecificWriteSideEffect(opcode) and
|
||||
tag = OnlyInstructionTag() and
|
||||
(
|
||||
opcode instanceof BufferAccessOpcode and
|
||||
t instanceof UnknownType
|
||||
type = getUnknownType()
|
||||
or
|
||||
not opcode instanceof BufferAccessOpcode and
|
||||
(
|
||||
t = arg.getUnspecifiedType().(DerivedType).getBaseType() and
|
||||
not t instanceof VoidType
|
||||
or
|
||||
arg.getUnspecifiedType().(DerivedType).getBaseType() instanceof VoidType and
|
||||
t instanceof UnknownType
|
||||
exists(Type baseType | baseType = arg.getUnspecifiedType().(DerivedType).getBaseType() |
|
||||
if baseType instanceof VoidType
|
||||
then type = getUnknownType()
|
||||
else type = getTypeForPRValueOrUnknown(baseType)
|
||||
)
|
||||
or
|
||||
index = -1 and
|
||||
not arg.getUnspecifiedType() instanceof DerivedType and
|
||||
t = arg.getUnspecifiedType()
|
||||
) and
|
||||
isGLValue = false
|
||||
type = getTypeForPRValueOrUnknown(arg.getUnspecifiedType())
|
||||
)
|
||||
or
|
||||
not isWrite() and
|
||||
hasSpecificReadSideEffect(opcode) and
|
||||
tag = OnlyInstructionTag() and
|
||||
t instanceof VoidType and
|
||||
isGLValue = false
|
||||
type = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -459,15 +446,21 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
|
||||
.getFullyConverted()).getResult()
|
||||
}
|
||||
|
||||
override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
tag instanceof OnlyInstructionTag and
|
||||
result = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and
|
||||
operandTag instanceof SideEffectOperandTag
|
||||
or
|
||||
tag instanceof OnlyInstructionTag and
|
||||
result = arg.getType().getUnspecifiedType() and
|
||||
not result instanceof DerivedType and
|
||||
operandTag instanceof SideEffectOperandTag
|
||||
override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
exists(Type operandType |
|
||||
tag instanceof OnlyInstructionTag and
|
||||
operandType = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and
|
||||
operandTag instanceof SideEffectOperandTag
|
||||
or
|
||||
tag instanceof OnlyInstructionTag and
|
||||
operandType = arg.getType().getUnspecifiedType() and
|
||||
not operandType instanceof DerivedType and
|
||||
operandTag instanceof SideEffectOperandTag
|
||||
|
|
||||
// If the type we select is an incomplete type (e.g. a forward-declared `struct`), there will
|
||||
// not be a `CppType` that represents that type. In that case, fall back to `UnknownCppType`.
|
||||
result = getTypeForPRValueOrUnknown(operandType)
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasSpecificWriteSideEffect(Opcode op) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
@@ -37,9 +38,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() }
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -105,9 +104,7 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio
|
||||
result = getLeftOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -163,13 +160,10 @@ class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCond
|
||||
|
||||
override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
opcode instanceof Opcode::ConditionalBranch and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
@@ -54,19 +55,15 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getVariableType(getVariable()) and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getVariableType(getVariable()))
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getVariableType(getVariable()) and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(getVariableType(getVariable()))
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.IR
|
||||
private import semmle.code.cpp.ir.IRConfiguration
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
@@ -11,11 +12,6 @@ private import TranslatedStmt
|
||||
private import IRConstruction
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* Gets the built-in `int` type.
|
||||
*/
|
||||
Type getIntType() { result.(IntType).isImplicitlySigned() }
|
||||
|
||||
/**
|
||||
* Gets the "real" parent of `expr`. This predicate treats conversions as if
|
||||
* they were explicit nodes in the expression tree, rather than as implicit
|
||||
@@ -53,6 +49,9 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// constant value.
|
||||
isIRConstant(getRealParent(expr))
|
||||
or
|
||||
// Ignore descendants of `__assume` expressions, since we translated these to `NoOp`.
|
||||
getRealParent(expr) instanceof AssumeExpr
|
||||
or
|
||||
// The `DestructorCall` node for a `DestructorFieldDestruction` has a `FieldAccess`
|
||||
// node as its qualifier, but that `FieldAccess` does not have a child of its own.
|
||||
// We'll ignore that `FieldAccess`, and supply the receiver as part of the calling
|
||||
@@ -66,8 +65,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
)
|
||||
or
|
||||
// Do not translate input/output variables in GNU asm statements
|
||||
getRealParent(expr) instanceof AsmStmt
|
||||
or
|
||||
// getRealParent(expr) instanceof AsmStmt
|
||||
// or
|
||||
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
|
||||
or
|
||||
// We do not yet translate destructors properly, so for now we ignore any
|
||||
@@ -532,9 +531,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
* If the instruction does not return a result, `resultType` should be
|
||||
* `VoidType`.
|
||||
*/
|
||||
abstract predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
);
|
||||
abstract predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType);
|
||||
|
||||
/**
|
||||
* Gets the `Function` that contains this element.
|
||||
@@ -574,7 +571,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
* `tag` must be unique for each variable generated from the same AST node
|
||||
* (not just from the same `TranslatedElement`).
|
||||
*/
|
||||
predicate hasTempVariable(TempVariableTag tag, Type type) { none() }
|
||||
predicate hasTempVariable(TempVariableTag tag, CppType type) { none() }
|
||||
|
||||
/**
|
||||
* If the instruction specified by `tag` is a `FunctionInstruction`, gets the
|
||||
@@ -619,6 +616,8 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
*/
|
||||
int getInstructionResultSize(InstructionTag tag) { none() }
|
||||
|
||||
predicate needsUnknownOpaqueType(int byteSize) { none() }
|
||||
|
||||
/**
|
||||
* If the instruction specified by `tag` is a `StringConstantInstruction`,
|
||||
* gets the `StringLiteral` for that instruction.
|
||||
@@ -634,7 +633,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
* If the instruction specified by `tag` is a `CatchByTypeInstruction`,
|
||||
* gets the type of the exception to be caught.
|
||||
*/
|
||||
Type getInstructionExceptionType(InstructionTag tag) { none() }
|
||||
CppType getInstructionExceptionType(InstructionTag tag) { none() }
|
||||
|
||||
/**
|
||||
* If the instruction specified by `tag` is an `InheritanceConversionInstruction`,
|
||||
@@ -653,7 +652,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
/**
|
||||
* Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`.
|
||||
*/
|
||||
Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() }
|
||||
CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() }
|
||||
|
||||
/**
|
||||
* Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.IRType
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
@@ -51,10 +53,22 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
*/
|
||||
abstract predicate producesExprResult();
|
||||
|
||||
final CppType getResultType() {
|
||||
if isResultGLValue()
|
||||
then result = getTypeForGLValue(expr.getType())
|
||||
else result = getTypeForPRValue(expr.getType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this expression.
|
||||
* Holds if the result of this `TranslatedExpr` is a glvalue.
|
||||
*/
|
||||
final Type getResultType() { result = expr.getUnspecifiedType() }
|
||||
private predicate isResultGLValue() {
|
||||
expr.isGLValueCategory()
|
||||
or
|
||||
// If this TranslatedExpr doesn't produce the result, then it must represent
|
||||
// a glvalue that is then loaded by a TranslatedLoad.
|
||||
not producesExprResult()
|
||||
}
|
||||
|
||||
final override Locatable getAST() { result = expr }
|
||||
|
||||
@@ -91,25 +105,6 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
|
||||
// is the only TranslatedExpr.
|
||||
ignoreLoad(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the result of this `TranslatedExpr` is a glvalue, or
|
||||
* `false` if the result is a prvalue.
|
||||
*
|
||||
* This predicate returns a `boolean` value instead of just a being a plain
|
||||
* predicate because all of the subclass predicates that call it require a
|
||||
* `boolean` value.
|
||||
*/
|
||||
final boolean isResultGLValue() {
|
||||
if
|
||||
expr.isGLValueCategory()
|
||||
or
|
||||
// If this TranslatedExpr doesn't produce the result, then it must represent
|
||||
// a glvalue that is then loaded by a TranslatedLoad.
|
||||
not producesExprResult()
|
||||
then result = true
|
||||
else result = false
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
@@ -120,38 +115,32 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
|
||||
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
(
|
||||
tag = ConditionValueTrueTempAddressTag() or
|
||||
tag = ConditionValueFalseTempAddressTag() or
|
||||
tag = ConditionValueResultTempAddressTag()
|
||||
) and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(expr.getType())
|
||||
or
|
||||
(
|
||||
tag = ConditionValueTrueConstantTag() or
|
||||
tag = ConditionValueFalseConstantTag()
|
||||
) and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
resultType = getResultType()
|
||||
or
|
||||
(
|
||||
tag = ConditionValueTrueStoreTag() or
|
||||
tag = ConditionValueFalseStoreTag()
|
||||
) and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
resultType = getResultType()
|
||||
or
|
||||
tag = ConditionValueResultLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -212,9 +201,9 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasTempVariable(TempVariableTag tag, Type type) {
|
||||
override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
tag = ConditionValueTempVar() and
|
||||
type = getResultType()
|
||||
type = getTypeForPRValue(expr.getType())
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
@@ -262,13 +251,10 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = LoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = expr.getUnspecifiedType() and
|
||||
if expr.isGLValueCategory() then isGLValue = true else isGLValue = false
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -324,9 +310,7 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
||||
child = getRightOperand() and result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -341,6 +325,10 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
}
|
||||
|
||||
private int getElementSize(Type type) {
|
||||
result = max(type.getUnspecifiedType().(PointerType).getBaseType().getSize())
|
||||
}
|
||||
|
||||
abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
override CrementOperation expr;
|
||||
|
||||
@@ -349,9 +337,9 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
final override string getInstructionConstantValue(InstructionTag tag) {
|
||||
tag = CrementConstantTag() and
|
||||
exists(Type resultType |
|
||||
resultType = getResultType() and
|
||||
resultType = expr.getUnspecifiedType() and
|
||||
(
|
||||
resultType instanceof IntegralType and result = "1"
|
||||
resultType instanceof IntegralOrEnumType and result = "1"
|
||||
or
|
||||
resultType instanceof FloatingPointType and result = "1.0"
|
||||
or
|
||||
@@ -360,38 +348,34 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
)
|
||||
}
|
||||
|
||||
private Type getConstantType() {
|
||||
private CppType getConstantType() {
|
||||
exists(Type resultType |
|
||||
resultType = getResultType() and
|
||||
resultType = expr.getUnspecifiedType() and
|
||||
(
|
||||
resultType instanceof ArithmeticType and result = resultType
|
||||
resultType instanceof ArithmeticType and
|
||||
result = getTypeForPRValue(expr.getType())
|
||||
or
|
||||
resultType instanceof PointerType and result = getIntType()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
isGLValue = false and
|
||||
(
|
||||
tag = CrementLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getResultType()
|
||||
or
|
||||
tag = CrementConstantTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getConstantType()
|
||||
or
|
||||
tag = CrementOpTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getResultType()
|
||||
or
|
||||
tag = CrementStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType()
|
||||
)
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = CrementLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
or
|
||||
tag = CrementConstantTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getConstantType()
|
||||
or
|
||||
tag = CrementOpTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
or
|
||||
tag = CrementStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -452,7 +436,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
getOpcode() instanceof Opcode::PointerAdd or
|
||||
getOpcode() instanceof Opcode::PointerSub
|
||||
) and
|
||||
result = max(getResultType().(PointerType).getBaseType().getSize())
|
||||
result = getElementSize(expr.getType())
|
||||
}
|
||||
|
||||
final TranslatedExpr getOperand() {
|
||||
@@ -461,7 +445,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
|
||||
final Opcode getOpcode() {
|
||||
exists(Type resultType |
|
||||
resultType = getResultType() and
|
||||
resultType = expr.getUnspecifiedType() and
|
||||
(
|
||||
(
|
||||
expr instanceof IncrementOperation and
|
||||
@@ -542,13 +526,10 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
||||
|
||||
override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(expr.getType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -564,7 +545,7 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
||||
|
||||
override int getInstructionElementSize(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = max(getResultType().getSize())
|
||||
result = max(expr.getUnspecifiedType().getSize())
|
||||
}
|
||||
|
||||
private TranslatedExpr getBaseOperand() {
|
||||
@@ -587,9 +568,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr {
|
||||
child = getOperand() and result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -640,13 +619,10 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
||||
|
||||
final override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::CopyValue and
|
||||
resultType = expr.getUnspecifiedType() and
|
||||
isGLValue = false
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
|
||||
@@ -707,13 +683,10 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(expr.getType())
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
@@ -733,13 +706,10 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
|
||||
result = getQualifier().getResult()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(expr.getType())
|
||||
}
|
||||
|
||||
override Field getInstructionField(InstructionTag tag) {
|
||||
@@ -763,13 +733,10 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
resultType = expr.getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
@@ -811,15 +778,10 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getResultType() and
|
||||
if expr.isGLValueCategory() or expr.hasLValueToRValueConversion()
|
||||
then isGLValue = true
|
||||
else isGLValue = false
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -865,13 +827,10 @@ abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr
|
||||
*/
|
||||
abstract Opcode getOpcode();
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
opcode = getOpcode() and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
|
||||
@@ -945,13 +904,10 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
child = getOperand() and result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
|
||||
@@ -996,7 +952,7 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
|
||||
|
||||
override Opcode getOpcode() {
|
||||
exists(Type resultType |
|
||||
resultType = getResultType() and
|
||||
resultType = expr.getUnspecifiedType() and
|
||||
if resultType instanceof PointerType
|
||||
then
|
||||
if resultType.(PointerType).getBaseType() instanceof VoidType
|
||||
@@ -1054,19 +1010,14 @@ class TranslatedBoolConversion extends TranslatedConversion {
|
||||
child = getOperand() and result = getInstruction(BoolConversionConstantTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
isGLValue = false and
|
||||
(
|
||||
tag = BoolConversionConstantTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getOperand().getResultType()
|
||||
or
|
||||
tag = BoolConversionCompareTag() and
|
||||
opcode instanceof Opcode::CompareNE and
|
||||
resultType instanceof BoolType
|
||||
)
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = BoolConversionConstantTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getOperand().getResultType()
|
||||
or
|
||||
tag = BoolConversionCompareTag() and
|
||||
opcode instanceof Opcode::CompareNE and
|
||||
resultType = getBoolType()
|
||||
}
|
||||
|
||||
override Instruction getResult() { result = getInstruction(BoolConversionCompareTag()) }
|
||||
@@ -1197,7 +1148,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
|
||||
opcode instanceof Opcode::PointerSub or
|
||||
opcode instanceof Opcode::PointerDiff
|
||||
) and
|
||||
result = max(getPointerOperand().getResultType().(PointerType).getBaseType().getSize())
|
||||
result = getElementSize(getPointerOperand().getExpr().getType())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1282,13 +1233,10 @@ class TranslatedAssignExpr extends TranslatedAssignment {
|
||||
result = getInstruction(AssignmentStoreTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = AssignmentStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(expr.getType()) // Always a prvalue
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -1365,14 +1313,16 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
// anyway. If we really want to model this case perfectly, we'll need the
|
||||
// extractor to tell us what the promoted type of the left operand would
|
||||
// be.
|
||||
result = getLeftOperand().getResultType()
|
||||
result = getLeftOperand().getExpr().getType()
|
||||
else
|
||||
// The right operand has already been converted to the type of the op.
|
||||
result = getRightOperand().getResultType()
|
||||
result = getRightOperand().getExpr().getType()
|
||||
}
|
||||
|
||||
private predicate leftOperandNeedsConversion() {
|
||||
getConvertedLeftOperandType() != getLeftOperand().getResultType()
|
||||
getConvertedLeftOperandType().getUnspecifiedType() != getLeftOperand()
|
||||
.getExpr()
|
||||
.getUnspecifiedType()
|
||||
}
|
||||
|
||||
private Opcode getOpcode() {
|
||||
@@ -1401,32 +1351,27 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
expr instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
isGLValue = false and
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = AssignOperationLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getTypeForPRValue(getLeftOperand().getExpr().getType())
|
||||
or
|
||||
tag = AssignOperationOpTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getTypeForPRValue(getConvertedLeftOperandType())
|
||||
or
|
||||
tag = AssignmentStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getTypeForPRValue(expr.getType()) // Always a prvalue
|
||||
or
|
||||
leftOperandNeedsConversion() and
|
||||
opcode instanceof Opcode::Convert and
|
||||
(
|
||||
tag = AssignOperationLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getLeftOperand().getResultType()
|
||||
tag = AssignOperationConvertLeftTag() and
|
||||
resultType = getTypeForPRValue(getConvertedLeftOperandType())
|
||||
or
|
||||
tag = AssignOperationOpTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getConvertedLeftOperandType()
|
||||
or
|
||||
tag = AssignmentStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType()
|
||||
or
|
||||
leftOperandNeedsConversion() and
|
||||
opcode instanceof Opcode::Convert and
|
||||
(
|
||||
tag = AssignOperationConvertLeftTag() and
|
||||
resultType = getConvertedLeftOperandType()
|
||||
or
|
||||
tag = AssignOperationConvertResultTag() and
|
||||
resultType = getLeftOperand().getResultType()
|
||||
)
|
||||
tag = AssignOperationConvertResultTag() and
|
||||
resultType = getTypeForPRValue(getLeftOperand().getExpr().getType())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1436,7 +1381,7 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
opcode = getOpcode() and
|
||||
(opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub)
|
||||
) and
|
||||
result = max(getResultType().(PointerType).getBaseType().getSize())
|
||||
result = getElementSize(expr.getType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -1518,13 +1463,10 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(AllocationSizeTag()) }
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = AllocationSizeTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(expr.getAllocator().getParameter(0).getType())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -1557,11 +1499,8 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getExtent().getFirstInstruction() }
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
isGLValue = false and
|
||||
resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
resultType = getTypeForPRValue(expr.getAllocator().getParameter(0).getType()) and
|
||||
(
|
||||
// Convert the extent to `size_t`, because the AST doesn't do this already.
|
||||
tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert
|
||||
@@ -1633,7 +1572,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
|
||||
tag = CallTargetTag() and result = expr.getAllocator()
|
||||
}
|
||||
|
||||
final override Type getCallResultType() { result = expr.getAllocator().getUnspecifiedType() }
|
||||
final override Type getCallResultType() { result = expr.getAllocator().getType() }
|
||||
|
||||
final override TranslatedExpr getQualifier() { none() }
|
||||
|
||||
@@ -1688,13 +1627,10 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
|
||||
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = getDestructorCall() }
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
resultType = expr.getTarget().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(expr.getTarget().getType())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -1741,9 +1677,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
||||
|
||||
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
not resultIsVoid() and
|
||||
(
|
||||
(
|
||||
@@ -1754,8 +1688,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
||||
tag = ConditionValueResultTempAddressTag()
|
||||
) and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
(
|
||||
if expr.isGLValueCategory()
|
||||
then resultType = getTypeForGLValue(any(UnknownType t)) // glvalue to a glvalue
|
||||
else resultType = getTypeForGLValue(expr.getType()) // glvalue to the result type
|
||||
)
|
||||
or
|
||||
(
|
||||
not thenIsVoid() and tag = ConditionValueTrueStoreTag()
|
||||
@@ -1763,13 +1700,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
||||
not elseIsVoid() and tag = ConditionValueFalseStoreTag()
|
||||
) and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
resultType = getResultType()
|
||||
or
|
||||
tag = ConditionValueResultLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
resultType = getResultType()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1837,7 +1772,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasTempVariable(TempVariableTag tag, Type type) {
|
||||
override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
not resultIsVoid() and
|
||||
tag = ConditionValueTempVar() and
|
||||
type = getResultType()
|
||||
@@ -1897,7 +1832,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
||||
}
|
||||
|
||||
private predicate thenIsVoid() {
|
||||
getThen().getResultType() instanceof VoidType
|
||||
getThen().getResultType().getIRType() instanceof IRVoidType
|
||||
or
|
||||
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
||||
// thrown, rather than `void`. Handle that case here.
|
||||
@@ -1905,14 +1840,14 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
||||
}
|
||||
|
||||
private predicate elseIsVoid() {
|
||||
getElse().getResultType() instanceof VoidType
|
||||
getElse().getResultType().getIRType() instanceof IRVoidType
|
||||
or
|
||||
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
||||
// thrown, rather than `void`. Handle that case here.
|
||||
expr.getElse() instanceof ThrowExpr
|
||||
}
|
||||
|
||||
private predicate resultIsVoid() { getResultType() instanceof VoidType }
|
||||
private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1921,13 +1856,10 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
||||
abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||
override ThrowExpr expr;
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = ThrowTag() and
|
||||
opcode = getThrowOpcode() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -1954,15 +1886,12 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType, isGLValue)
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getExceptionType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getExceptionType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -1983,9 +1912,9 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
|
||||
result = getIRTempVariable(expr, ThrowTempVar())
|
||||
}
|
||||
|
||||
final override predicate hasTempVariable(TempVariableTag tag, Type type) {
|
||||
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
tag = ThrowTempVar() and
|
||||
type = getExceptionType()
|
||||
type = getTypeForPRValue(getExceptionType())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -1999,10 +1928,10 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
|
||||
)
|
||||
}
|
||||
|
||||
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
tag = ThrowTag() and
|
||||
operandTag instanceof LoadOperandTag and
|
||||
result = getExceptionType()
|
||||
result = getTypeForPRValue(getExceptionType())
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
@@ -2017,7 +1946,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
|
||||
|
||||
final override Opcode getThrowOpcode() { result instanceof Opcode::ThrowValue }
|
||||
|
||||
private Type getExceptionType() { result = expr.getUnspecifiedType() }
|
||||
private Type getExceptionType() { result = expr.getType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2075,13 +2004,10 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -2148,13 +2074,10 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr, In
|
||||
id = 1 and result = getInitialization()
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::Convert and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
@@ -2315,9 +2238,7 @@ class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
|
||||
child = getConditionExpr() and result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -2366,23 +2287,18 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont
|
||||
result = getInstruction(LoadTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(expr.getType())
|
||||
or
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
or
|
||||
tag = LoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -2408,16 +2324,16 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont
|
||||
result = getTempVariable(LambdaTempVar())
|
||||
}
|
||||
|
||||
override predicate hasTempVariable(TempVariableTag tag, Type type) {
|
||||
override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
tag = LambdaTempVar() and
|
||||
type = getResultType()
|
||||
type = getTypeForPRValue(expr.getType())
|
||||
}
|
||||
|
||||
final override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
final override Type getTargetType() { result = getResultType() }
|
||||
final override Type getTargetType() { result = expr.getType() }
|
||||
|
||||
private predicate hasInitializer() { exists(getInitialization()) }
|
||||
|
||||
@@ -2448,13 +2364,10 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr {
|
||||
result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
opcode instanceof Opcode::CopyValue and
|
||||
tag instanceof OnlyInstructionTag and
|
||||
resultType = expr.getType() and
|
||||
isGLValue = false
|
||||
resultType = getResultType()
|
||||
}
|
||||
|
||||
override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
|
||||
@@ -2489,3 +2402,26 @@ class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
|
||||
|
||||
final override Opcode getOpcode() { result instanceof Opcode::Error }
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of an `__assume` expression. We currently translate these as `NoOp`. In the
|
||||
* future, we will probably want to do something better. At a minimum, we can model `__assume(0)` as
|
||||
* `Unreached`.
|
||||
*/
|
||||
class TranslatedAssumeExpr extends TranslatedSingleInstructionExpr {
|
||||
override AssumeExpr expr;
|
||||
|
||||
final override Opcode getOpcode() { result instanceof Opcode::NoOp }
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
final override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private import cpp
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
@@ -115,55 +116,46 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
or
|
||||
(
|
||||
child = getDestructorDestructionList() and
|
||||
if getReturnType() instanceof VoidType
|
||||
then result = getInstruction(ReturnTag())
|
||||
else result = getInstruction(ReturnValueAddressTag())
|
||||
if hasReturnValue()
|
||||
then result = getInstruction(ReturnValueAddressTag())
|
||||
else result = getInstruction(ReturnTag())
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
(
|
||||
tag = EnterFunctionTag() and
|
||||
opcode instanceof Opcode::EnterFunction and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
or
|
||||
tag = UnmodeledDefinitionTag() and
|
||||
opcode instanceof Opcode::UnmodeledDefinition and
|
||||
resultType instanceof UnknownType and
|
||||
isGLValue = false
|
||||
resultType = getUnknownType()
|
||||
or
|
||||
tag = AliasedDefinitionTag() and
|
||||
opcode instanceof Opcode::AliasedDefinition and
|
||||
resultType instanceof UnknownType and
|
||||
isGLValue = false
|
||||
resultType = getUnknownType()
|
||||
or
|
||||
tag = InitializeThisTag() and
|
||||
opcode instanceof Opcode::InitializeThis and
|
||||
resultType = getThisType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getThisType())
|
||||
or
|
||||
tag = ReturnValueAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getReturnType() and
|
||||
not resultType instanceof VoidType and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getReturnType()) and
|
||||
hasReturnValue()
|
||||
or
|
||||
(
|
||||
tag = ReturnTag() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false and
|
||||
if getReturnType() instanceof VoidType
|
||||
then opcode instanceof Opcode::ReturnVoid
|
||||
else opcode instanceof Opcode::ReturnValue
|
||||
resultType = getVoidType() and
|
||||
if hasReturnValue()
|
||||
then opcode instanceof Opcode::ReturnValue
|
||||
else opcode instanceof Opcode::ReturnVoid
|
||||
)
|
||||
or
|
||||
tag = UnwindTag() and
|
||||
opcode instanceof Opcode::Unwind and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false and
|
||||
resultType = getVoidType() and
|
||||
(
|
||||
// Only generate the `Unwind` instruction if there is any exception
|
||||
// handling present in the function.
|
||||
@@ -173,13 +165,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
or
|
||||
tag = UnmodeledUseTag() and
|
||||
opcode instanceof Opcode::UnmodeledUse and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
or
|
||||
tag = ExitFunctionTag() and
|
||||
opcode instanceof Opcode::ExitFunction and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -198,7 +188,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
result = getUnmodeledDefinitionInstruction()
|
||||
or
|
||||
tag = ReturnTag() and
|
||||
not getReturnType() instanceof VoidType and
|
||||
hasReturnValue() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ReturnValueAddressTag())
|
||||
@@ -208,11 +198,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
)
|
||||
}
|
||||
|
||||
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
tag = ReturnTag() and
|
||||
not getReturnType() instanceof VoidType and
|
||||
hasReturnValue() and
|
||||
operandTag instanceof LoadOperandTag and
|
||||
result = getReturnType()
|
||||
result = getTypeForPRValue(getReturnType())
|
||||
}
|
||||
|
||||
final override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
@@ -220,10 +210,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
result = getReturnVariable()
|
||||
}
|
||||
|
||||
final override predicate hasTempVariable(TempVariableTag tag, Type type) {
|
||||
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
tag = ReturnValueTempVar() and
|
||||
type = getReturnType() and
|
||||
not type instanceof VoidType
|
||||
hasReturnValue() and
|
||||
type = getTypeForPRValue(getReturnType())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,6 +231,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
result = getIRTempVariable(func, ReturnValueTempVar())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function has a non-`void` return type.
|
||||
*/
|
||||
final predicate hasReturnValue() { not func.getUnspecifiedType() instanceof VoidType }
|
||||
|
||||
/**
|
||||
* Gets the single `UnmodeledDefinition` instruction for this function.
|
||||
*/
|
||||
@@ -271,7 +266,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
* parameters and local variables, plus any global variables or static data members that are
|
||||
* directly accessed by the function.
|
||||
*/
|
||||
final predicate hasUserVariable(Variable var, Type type) {
|
||||
final predicate hasUserVariable(Variable var, CppType type) {
|
||||
(
|
||||
(
|
||||
var instanceof GlobalOrNamespaceVariable
|
||||
@@ -287,10 +282,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
or
|
||||
var.(Parameter).getCatchBlock().getEnclosingFunction() = func
|
||||
) and
|
||||
type = getVariableType(var)
|
||||
type = getTypeForPRValue(getVariableType(var))
|
||||
}
|
||||
|
||||
final private Type getReturnType() { result = func.getUnspecifiedType() }
|
||||
final Type getReturnType() { result = func.getType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,18 +330,14 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getVariableType(param) and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getVariableType(param))
|
||||
or
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::InitializeParameter and
|
||||
resultType = getVariableType(param) and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(getVariableType(param))
|
||||
}
|
||||
|
||||
final override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
@@ -404,9 +395,7 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
|
||||
else result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -469,9 +458,7 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
|
||||
else result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
@@ -79,9 +80,7 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -150,13 +149,10 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
|
||||
not expr instanceof StringLiteral
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getContext().getTargetType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(getContext().getTargetType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -188,20 +184,16 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
|
||||
class TranslatedStringLiteralInitialization extends TranslatedDirectInitialization {
|
||||
override StringLiteral expr;
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
// Load the string literal to make it a prvalue of type `char[len]`
|
||||
tag = InitializerLoadStringTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getInitializer().getResultType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
or
|
||||
// Store the string into the target.
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getInitializer().getResultType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
or
|
||||
exists(int startIndex, int elementCount |
|
||||
// If the initializer string isn't large enough to fill the target, then
|
||||
@@ -213,26 +205,22 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
// space in the target array.
|
||||
tag = ZeroPadStringConstantTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType instanceof UnknownType and
|
||||
isGLValue = false
|
||||
resultType = getUnknownOpaqueType(elementCount * getElementType().getSize())
|
||||
or
|
||||
// The index of the first element to be zero initialized.
|
||||
tag = ZeroPadStringElementIndexTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getIntType() and
|
||||
isGLValue = false
|
||||
resultType = getIntType()
|
||||
or
|
||||
// Compute the address of the first element to be zero initialized.
|
||||
tag = ZeroPadStringElementAddressTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getElementType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getElementType())
|
||||
or
|
||||
// Store the constant zero into the remainder of the string.
|
||||
tag = ZeroPadStringStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType instanceof UnknownType and
|
||||
isGLValue = false
|
||||
resultType = getUnknownOpaqueType(elementCount * getElementType().getSize())
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -326,6 +314,13 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
)
|
||||
}
|
||||
|
||||
override predicate needsUnknownOpaqueType(int byteSize) {
|
||||
exists(int elementCount |
|
||||
zeroInitRange(_, elementCount) and
|
||||
byteSize = elementCount * getElementType().getSize()
|
||||
)
|
||||
}
|
||||
|
||||
override int getInstructionResultSize(InstructionTag tag) {
|
||||
exists(int elementCount |
|
||||
zeroInitRange(_, elementCount) and
|
||||
@@ -338,7 +333,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
}
|
||||
|
||||
private Type getElementType() {
|
||||
result = getContext().getTargetType().(ArrayType).getBaseType().getUnspecifiedType()
|
||||
result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,7 +343,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
private predicate zeroInitRange(int startIndex, int elementCount) {
|
||||
exists(int targetCount |
|
||||
startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and
|
||||
targetCount = getContext().getTargetType().(ArrayType).getArraySize() and
|
||||
targetCount = getContext().getTargetType().getUnspecifiedType().(ArrayType).getArraySize() and
|
||||
elementCount = targetCount - startIndex and
|
||||
elementCount > 0
|
||||
)
|
||||
@@ -359,9 +354,7 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization
|
||||
StructorCallContext {
|
||||
override ConstructorCall expr;
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -412,13 +405,10 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
*/
|
||||
final int getOrder() { result = field.getInitializationOrder() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = getFieldAddressTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
resultType = field.getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(field.getType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -481,20 +471,16 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
TTranslatedFieldValueInitialization {
|
||||
TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue)
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = getFieldDefaultValueTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = field.getUnspecifiedType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(field.getType())
|
||||
or
|
||||
tag = getFieldDefaultValueStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = field.getUnspecifiedType() and
|
||||
isGLValue = false
|
||||
resultType = getTypeForPRValue(field.getUnspecifiedType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -557,18 +543,14 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = getElementIndexTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getIntType() and
|
||||
isGLValue = false
|
||||
resultType = getIntType()
|
||||
or
|
||||
tag = getElementAddressTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getElementType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getElementType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -606,7 +588,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
|
||||
final ArrayOrVectorAggregateLiteral getInitList() { result = initList }
|
||||
|
||||
final Type getElementType() { result = initList.getElementType().getUnspecifiedType() }
|
||||
final Type getElementType() { result = initList.getElementType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -659,20 +641,16 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
this = TTranslatedElementValueInitialization(initList, elementIndex, elementCount)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue)
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = getElementDefaultValueTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getDefaultValueType() and
|
||||
isGLValue = false
|
||||
resultType = getDefaultValueType()
|
||||
or
|
||||
tag = getElementDefaultValueStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getDefaultValueType() and
|
||||
isGLValue = false
|
||||
resultType = getDefaultValueType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -726,6 +704,10 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
|
||||
override int getElementIndex() { result = elementIndex }
|
||||
|
||||
override predicate needsUnknownOpaqueType(int byteSize) {
|
||||
elementCount != 0 and byteSize = elementCount * getElementType().getSize()
|
||||
}
|
||||
|
||||
private InstructionTag getElementDefaultValueTag() {
|
||||
result = InitializerElementDefaultValueTag()
|
||||
}
|
||||
@@ -734,8 +716,10 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
result = InitializerElementDefaultValueStoreTag()
|
||||
}
|
||||
|
||||
private Type getDefaultValueType() {
|
||||
if elementCount = 1 then result = getElementType() else result instanceof UnknownType
|
||||
private CppType getDefaultValueType() {
|
||||
if elementCount = 1
|
||||
then result = getTypeForPRValue(getElementType())
|
||||
else result = getUnknownOpaqueType(elementCount * getElementType().getSize())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,13 +750,10 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
|
||||
abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStructor {
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::ConvertToBase and
|
||||
resultType = call.getTarget().getDeclaringType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(call.getTarget().getDeclaringType())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -822,9 +803,7 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
|
||||
result = getStructorCall().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
@@ -35,13 +36,10 @@ class TranslatedEmptyStmt extends TranslatedStmt {
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -63,9 +61,7 @@ class TranslatedDeclStmt extends TranslatedStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) { result = getDeclarationEntry(id) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -112,9 +108,7 @@ class TranslatedExprStmt extends TranslatedStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getExpr() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -145,13 +139,10 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getEnclosingFunction().getReturnVariable().getType() and
|
||||
isGLValue = true
|
||||
resultType = getTypeForGLValue(getEnclosingFunction().getReturnType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -174,7 +165,7 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = getEnclosingFunction().getReturnVariable().getType() }
|
||||
override Type getTargetType() { result = getEnclosingFunction().getReturnType() }
|
||||
|
||||
TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(stmt.getExpr().getFullyConverted())
|
||||
@@ -188,13 +179,10 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -218,9 +206,7 @@ class TranslatedTryStmt extends TranslatedStmt {
|
||||
result = getHandler(id - 1)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -262,14 +248,11 @@ class TranslatedBlock extends TranslatedStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) { result = getStmt(id) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
isEmpty() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
@@ -330,13 +313,10 @@ abstract class TranslatedHandler extends TranslatedStmt {
|
||||
class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
TranslatedCatchByTypeHandler() { exists(stmt.getParameter()) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = CatchTag() and
|
||||
opcode instanceof Opcode::CatchByType and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
@@ -362,9 +342,9 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
)
|
||||
}
|
||||
|
||||
override Type getInstructionExceptionType(InstructionTag tag) {
|
||||
override CppType getInstructionExceptionType(InstructionTag tag) {
|
||||
tag = CatchTag() and
|
||||
result = stmt.getParameter().getType()
|
||||
result = getTypeForPRValue(stmt.getParameter().getType())
|
||||
}
|
||||
|
||||
private TranslatedParameter getParameter() {
|
||||
@@ -378,13 +358,10 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
class TranslatedCatchAnyHandler extends TranslatedHandler {
|
||||
TranslatedCatchAnyHandler() { not exists(stmt.getParameter()) }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = CatchTag() and
|
||||
opcode instanceof Opcode::CatchAny and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -436,9 +413,7 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
@@ -466,9 +441,7 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
|
||||
id = 1 and result = getBody()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -597,9 +570,7 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
result = getCondition().getFirstInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -649,13 +620,10 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -693,13 +661,10 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
id = 1 and result = getBody()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = SwitchBranchTag() and
|
||||
opcode instanceof Opcode::Switch and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -727,37 +692,20 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
class TranslatedAsmStmt extends TranslatedStmt {
|
||||
override AsmStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
override TranslatedExpr getChild(int id) {
|
||||
result = getTranslatedExpr(stmt.getChild(id).(Expr).getFullyConverted())
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if exists(stmt.getChild(0))
|
||||
then result = getInstruction(AsmInputTag(0))
|
||||
if exists(getChild(0))
|
||||
then result = getChild(0).getFirstInstruction()
|
||||
else result = getInstruction(AsmTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
|
||||
) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = AsmTag() and
|
||||
opcode instanceof Opcode::InlineAsm and
|
||||
resultType instanceof UnknownType and
|
||||
isGLValue = false
|
||||
or
|
||||
exists(int index, VariableAccess va |
|
||||
tag = AsmInputTag(index) and
|
||||
stmt.getChild(index) = va and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = va.getType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
)
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
exists(int index |
|
||||
tag = AsmInputTag(index) and
|
||||
result = getIRUserVariable(stmt.getEnclosingFunction(),
|
||||
stmt.getChild(index).(VariableAccess).getTarget())
|
||||
)
|
||||
resultType = getUnknownType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -768,29 +716,28 @@ class TranslatedAsmStmt extends TranslatedStmt {
|
||||
exists(int index |
|
||||
tag = AsmTag() and
|
||||
operandTag = asmOperand(index) and
|
||||
result = getInstruction(AsmInputTag(index))
|
||||
result = getChild(index).getResult()
|
||||
)
|
||||
}
|
||||
|
||||
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
tag = AsmTag() and
|
||||
operandTag instanceof SideEffectOperandTag and
|
||||
result instanceof UnknownType
|
||||
result = getUnknownType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = AsmTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
exists(int index |
|
||||
tag = AsmInputTag(index) and
|
||||
kind instanceof GotoEdge and
|
||||
if exists(stmt.getChild(index + 1))
|
||||
then result = getInstruction(AsmInputTag(index + 1))
|
||||
child = getChild(index) and
|
||||
if exists(getChild(index + 1))
|
||||
then result = getChild(index + 1).getFirstInstruction()
|
||||
else result = getInstruction(AsmTag())
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRVariable
|
||||
import Operand
|
||||
private import internal.IRImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::IRType
|
||||
import Imports::MemoryAccessKind
|
||||
|
||||
private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
|
||||
@@ -5,6 +5,7 @@ import Imports::TempVariableTag
|
||||
private import Imports::IRUtilities
|
||||
private import Imports::TTempVariableTag
|
||||
private import Imports::TIRVariable
|
||||
private import Imports::IRType
|
||||
|
||||
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
|
||||
result.getVariable() = var and
|
||||
@@ -24,7 +25,17 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::Type getType();
|
||||
final Language::Type getType() { getLanguageType().hasType(result, false) }
|
||||
|
||||
/**
|
||||
* Gets the language-neutral type of the variable.
|
||||
*/
|
||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
@@ -59,7 +70,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::Type type;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRUserVariable() { this = TIRUserVariable(var, type, func) }
|
||||
|
||||
@@ -71,7 +82,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
}
|
||||
|
||||
final override Language::Type getType() { result = type }
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
@@ -110,11 +121,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Language::AST ast;
|
||||
TempVariableTag tag;
|
||||
Language::Type type;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
|
||||
final override Language::Type getType() { result = type }
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRVariable
|
||||
import Operand
|
||||
private import internal.InstructionImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::IRType
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
@@ -113,10 +114,12 @@ module InstructionSanity {
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func |
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
func = operand.getUse().getEnclosingFunction() and
|
||||
message = "Operand missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString()
|
||||
+ "' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -321,7 +324,7 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if getResultType() instanceof Language::VoidType
|
||||
if getResultIRType() instanceof IRVoidType
|
||||
then result = "v"
|
||||
else
|
||||
if hasMemoryResult()
|
||||
@@ -353,23 +356,6 @@ class Instruction extends Construction::TInstruction {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isGLValue() then result = "glval<" + type + ">" else result = type
|
||||
}
|
||||
|
||||
string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if
|
||||
getResultType() instanceof Language::UnknownType and
|
||||
not isGLValue() and
|
||||
exists(getResultSize())
|
||||
then result = valcat + "[" + getResultSize().toString() + "]"
|
||||
else result = valcat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -389,7 +375,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*
|
||||
* Example: `r1_1(int*)`
|
||||
*/
|
||||
final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" }
|
||||
final string getResultString() {
|
||||
result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
@@ -457,6 +445,16 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
final Language::LanguageType getResultLanguageType() {
|
||||
result = Construction::getInstructionResultType(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
* instruction does not produce a result, its result type will be `VoidType`.
|
||||
@@ -464,7 +462,16 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `isGLValue()` holds, then the result type of this instruction should be
|
||||
* thought of as "pointer to `getResultType()`".
|
||||
*/
|
||||
final Language::Type getResultType() { Construction::instructionHasType(this, result, _) }
|
||||
final Language::Type getResultType() {
|
||||
exists(Language::LanguageType resultType |
|
||||
resultType = getResultLanguageType() and
|
||||
(
|
||||
resultType.hasUnspecifiedType(result, _)
|
||||
or
|
||||
not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the result produced by this instruction is a glvalue. If this
|
||||
@@ -484,7 +491,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isGLValue() { Construction::instructionHasType(this, _, true) }
|
||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
@@ -493,16 +500,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
final int getResultSize() {
|
||||
if isGLValue()
|
||||
then
|
||||
// a glvalue is always pointer-sized.
|
||||
result = Language::getPointerSize()
|
||||
else
|
||||
if getResultType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionResultSize(this)
|
||||
else result = Language::getTypeSize(getResultType())
|
||||
}
|
||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
||||
|
||||
/**
|
||||
* Gets the opcode that specifies the operation performed by this instruction.
|
||||
@@ -1384,7 +1382,7 @@ class CatchInstruction extends Instruction {
|
||||
* An instruction that catches an exception of a specific type.
|
||||
*/
|
||||
class CatchByTypeInstruction extends CatchInstruction {
|
||||
Language::Type exceptionType;
|
||||
Language::LanguageType exceptionType;
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
@@ -1396,7 +1394,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
/**
|
||||
* Gets the type of exception to be caught.
|
||||
*/
|
||||
final Language::Type getExceptionType() { result = exceptionType }
|
||||
final Language::LanguageType getExceptionType() { result = exceptionType }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
private import Instruction
|
||||
private import IRBlock
|
||||
private import internal.OperandImports as Imports
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Overlap
|
||||
private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
@@ -143,22 +144,40 @@ class Operand extends TOperand {
|
||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
Language::Type getType() { result = getAnyDef().getResultType() }
|
||||
Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
|
||||
|
||||
/**
|
||||
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
||||
* as the result type of the definition instruction consumed by this operand. For register
|
||||
* operands, this is always the case. For some memory operands, the operand type may be different
|
||||
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||
* result type of the definition instruction consumed by this operand. For register operands,
|
||||
* this is always the case. For some memory operands, the operand type may be different from
|
||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
final Language::Type getType() { getLanguageType().hasType(result, _) }
|
||||
|
||||
/**
|
||||
* Holds if the value consumed by this operand is a glvalue. If this
|
||||
* holds, the value of the operand represents the address of a location,
|
||||
* and the type of the location is given by `getType()`. If this does
|
||||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
* given by `getType()`.
|
||||
*/
|
||||
predicate isGLValue() { getAnyDef().isGLValue() }
|
||||
final predicate isGLValue() { getLanguageType().hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() { result = Language::getTypeSize(getType()) }
|
||||
final int getSize() { result = getLanguageType().getByteSize() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,11 +189,6 @@ class MemoryOperand extends Operand {
|
||||
this = TPhiOperand(_, _, _, _)
|
||||
}
|
||||
|
||||
override predicate isGLValue() {
|
||||
// A `MemoryOperand` can never be a glvalue
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the operand.
|
||||
*/
|
||||
@@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
class TypedOperand extends NonPhiMemoryOperand {
|
||||
override TypedOperandTag tag;
|
||||
|
||||
final override Language::Type getType() {
|
||||
final override Language::LanguageType getLanguageType() {
|
||||
result = Construction::getInstructionOperandType(useInstr, tag)
|
||||
}
|
||||
}
|
||||
@@ -381,12 +395,6 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
final override int getSize() {
|
||||
if getType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
useInstr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
private import cpp
|
||||
private import internal.ValueNumberingImports
|
||||
private import IR
|
||||
|
||||
/**
|
||||
@@ -23,31 +23,32 @@ newtype TValueNumber =
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, Type type, string value) {
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, Type type, string value) {
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, ValueNumber objectAddress) {
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand) {
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
ValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
@@ -59,7 +60,7 @@ newtype TValueNumber =
|
||||
class ValueNumber extends TValueNumber {
|
||||
final string toString() { result = getExampleInstruction().getResultId() }
|
||||
|
||||
final Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
@@ -150,23 +151,23 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, Type type, string value
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, Type type, string value
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Field field, ValueNumber objectAddress
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
@@ -174,43 +175,43 @@ private predicate fieldAddressValueNumber(
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, Type type, int elementSize,
|
||||
ValueNumber leftOperand, ValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, Class baseClass,
|
||||
Class derivedClass, ValueNumber operand
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
@@ -225,7 +226,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultType() instanceof VoidType and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
@@ -269,38 +270,41 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(Type type, string value |
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Type type, string value |
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Field field, ValueNumber objectAddress |
|
||||
exists(Language::Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Type type, ValueNumber operand |
|
||||
exists(Opcode opcode, IRType type, ValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand |
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
@@ -1,2 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag
|
||||
import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities
|
||||
import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
|
||||
@@ -4,34 +4,52 @@ private import Alias
|
||||
private import SSAConstruction
|
||||
private import DebugSSA
|
||||
|
||||
bindingset[offset]
|
||||
private string getKeySuffixForOffset(int offset) {
|
||||
if offset % 2 = 0 then result = "" else result = "_Chi"
|
||||
}
|
||||
|
||||
bindingset[offset]
|
||||
private int getIndexForOffset(int offset) { result = offset / 2 }
|
||||
|
||||
/**
|
||||
* Property provide that dumps the memory access of each result. Useful for debugging SSA
|
||||
* construction.
|
||||
*/
|
||||
class PropertyProvider extends IRPropertyProvider {
|
||||
override string getInstructionProperty(Instruction instruction, string key) {
|
||||
exists(MemoryLocation location |
|
||||
location = getResultMemoryLocation(instruction) and
|
||||
(
|
||||
key = "ResultMemoryLocation" and result = location.toString()
|
||||
or
|
||||
key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString()
|
||||
key = "ResultMemoryLocation" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getResultMemoryLocation(instruction)
|
||||
|
|
||||
loc.toString(), ","
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation location |
|
||||
location = getOperandMemoryLocation(instruction.getAnOperand()) and
|
||||
(
|
||||
key = "OperandMemoryAccess" and result = location.toString()
|
||||
or
|
||||
key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString()
|
||||
key = "ResultVirtualVariable" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getResultMemoryLocation(instruction)
|
||||
|
|
||||
loc.getVirtualVariable().toString(), ","
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
|
||||
defBlock.getInstruction(defIndex) = instruction and
|
||||
key = "DefinitionRank[" + useLocation.toString() + "]" and
|
||||
key = "OperandMemoryLocation" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getOperandMemoryLocation(instruction.getAnOperand())
|
||||
|
|
||||
loc.toString(), ","
|
||||
)
|
||||
or
|
||||
key = "OperandVirtualVariable" and
|
||||
result = strictconcat(MemoryLocation loc |
|
||||
loc = getOperandMemoryLocation(instruction.getAnOperand())
|
||||
|
|
||||
loc.getVirtualVariable().toString(), ","
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
|
||||
defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
|
||||
key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and
|
||||
result = defRank.toString()
|
||||
)
|
||||
or
|
||||
@@ -41,10 +59,11 @@ class PropertyProvider extends IRPropertyProvider {
|
||||
result = useRank.toString()
|
||||
)
|
||||
or
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
|
||||
defBlock.getInstruction(defIndex) = instruction and
|
||||
key = "DefinitionReachesUse[" + useLocation.toString() + "]" and
|
||||
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
|
||||
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
|
||||
defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
|
||||
key = "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString()
|
||||
+ "]" and
|
||||
result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
|
||||
exists(Instruction useInstruction |
|
||||
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import SSAConstructionInternal
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
private import SSAConstructionImports
|
||||
private import NewIR
|
||||
|
||||
private class OldBlock = Reachability::ReachableBlock;
|
||||
@@ -18,7 +15,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate functionHasIR(Function func) {
|
||||
predicate functionHasIR(Language::Function func) {
|
||||
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
|
||||
}
|
||||
|
||||
@@ -42,7 +39,7 @@ private module Cached {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
||||
hasChiNode(_, oldInstruction)
|
||||
} or
|
||||
Unreached(Function function) {
|
||||
Unreached(Language::Function function) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
function = oldInstruction.getEnclosingFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
@@ -50,12 +47,14 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
|
||||
predicate hasTempVariable(
|
||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
||||
) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getEnclosingFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getType() = type
|
||||
var.getLanguageType() = type
|
||||
)
|
||||
}
|
||||
|
||||
@@ -135,24 +134,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
|
||||
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instr) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
result = oldOperand.getType()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instr) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
// Only return a result for operands that need an explicit result size.
|
||||
oldOperand.getType() instanceof UnknownType and
|
||||
result = oldOperand.getSize()
|
||||
result = oldOperand.getLanguageType()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -196,20 +183,21 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
* the new instructions generated from the successors of the old instruction
|
||||
*/
|
||||
|
||||
cached
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
if hasChiNode(_, getOldInstruction(instruction))
|
||||
@@ -252,7 +240,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Locatable getInstructionAST(Instruction instruction) {
|
||||
Language::AST getInstructionAST(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction)
|
||||
or
|
||||
@@ -270,29 +258,25 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
|
||||
Language::LanguageType getInstructionResultType(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction) and
|
||||
type = oldInstruction.getResultType() and
|
||||
if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false
|
||||
result = oldInstruction.getResultLanguageType()
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
||||
instruction = Chi(oldInstruction) and
|
||||
hasChiNode(vvar, oldInstruction) and
|
||||
type = vvar.getType() and
|
||||
isGLValue = false
|
||||
result = vvar.getType()
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = Phi(_, location) and
|
||||
type = location.getType() and
|
||||
isGLValue = false
|
||||
result = location.getType()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(_) and
|
||||
type instanceof VoidType and
|
||||
isGLValue = false
|
||||
result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -338,7 +322,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Field getInstructionField(Instruction instruction) {
|
||||
Language::Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
@@ -348,7 +332,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Function getInstructionFunction(Instruction instruction) {
|
||||
Language::Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
@@ -358,19 +342,19 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
|
||||
}
|
||||
|
||||
cached
|
||||
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
|
||||
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
|
||||
result = getOldInstruction(instruction)
|
||||
.(OldIR::BuiltInOperationInstruction)
|
||||
.getBuiltInOperation()
|
||||
}
|
||||
|
||||
cached
|
||||
Type getInstructionExceptionType(Instruction instruction) {
|
||||
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
@@ -380,14 +364,9 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionResultSize(Instruction instruction) {
|
||||
// Only return a result for instructions that needed an explicit result size.
|
||||
instruction.getResultType() instanceof UnknownType and
|
||||
result = getOldInstruction(instruction).getResultSize()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
|
||||
predicate getInstructionInheritance(
|
||||
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
|
||||
) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
@@ -2,4 +2,5 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import SimpleSSA as Alias
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
import AliasAnalysis
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.raw.IR
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
private import SimpleSSAImports
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
private predicate hasResultMemoryAccess(
|
||||
Instruction instr, IRVariable var, Type type, IntValue bitOffset
|
||||
Instruction instr, IRVariable var, Language::LanguageType type, IntValue bitOffset
|
||||
) {
|
||||
resultPointsTo(instr.getResultAddressOperand().getAnyDef(), var, bitOffset) and
|
||||
type = instr.getResultType()
|
||||
type = instr.getResultLanguageType()
|
||||
}
|
||||
|
||||
private predicate hasOperandMemoryAccess(
|
||||
MemoryOperand operand, IRVariable var, Type type, IntValue bitOffset
|
||||
MemoryOperand operand, IRVariable var, Language::LanguageType type, IntValue bitOffset
|
||||
) {
|
||||
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, bitOffset) and
|
||||
type = operand.getType()
|
||||
type = operand.getLanguageType()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,17 +26,17 @@ private predicate isVariableModeled(IRVariable var) {
|
||||
not variableAddressEscapes(var) and
|
||||
// There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for
|
||||
// `type = var.getType()` is sufficient.
|
||||
forall(Instruction instr, Type type, IntValue bitOffset |
|
||||
forall(Instruction instr, Language::LanguageType type, IntValue bitOffset |
|
||||
hasResultMemoryAccess(instr, var, type, bitOffset)
|
||||
|
|
||||
bitOffset = 0 and
|
||||
type = var.getType()
|
||||
type.getIRType() = var.getIRType()
|
||||
) and
|
||||
forall(MemoryOperand operand, Type type, IntValue bitOffset |
|
||||
forall(MemoryOperand operand, Language::LanguageType type, IntValue bitOffset |
|
||||
hasOperandMemoryAccess(operand, var, type, bitOffset)
|
||||
|
|
||||
bitOffset = 0 and
|
||||
type = var.getType()
|
||||
type.getIRType() = var.getIRType()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,7 +55,7 @@ class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
final VirtualVariable getVirtualVariable() { result = this }
|
||||
|
||||
final Type getType() { result = var.getType() }
|
||||
final Language::LanguageType getType() { result = var.getLanguageType() }
|
||||
|
||||
final string getUniqueId() { result = var.getUniqueId() }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
507
cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll
Normal file
507
cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll
Normal file
@@ -0,0 +1,507 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.Print
|
||||
private import semmle.code.cpp.ir.implementation.IRType
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
|
||||
private int getPointerSize() { result = max(any(NullPointerType t).getSize()) }
|
||||
|
||||
/**
|
||||
* Works around an extractor bug where a function reference gets a size of one byte.
|
||||
*/
|
||||
private int getTypeSizeWorkaround(Type type) {
|
||||
exists(Type unspecifiedType |
|
||||
unspecifiedType = type.getUnspecifiedType() and
|
||||
(
|
||||
unspecifiedType instanceof FunctionReferenceType and
|
||||
result = getPointerSize()
|
||||
or
|
||||
exists(PointerToMemberType ptmType |
|
||||
ptmType = unspecifiedType and
|
||||
(
|
||||
if ptmType.getBaseType().getUnspecifiedType() instanceof RoutineType
|
||||
then result = getPointerSize() * 2
|
||||
else result = getPointerSize()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(ArrayType arrayType |
|
||||
// Treat `T[]` as `T*`.
|
||||
arrayType = unspecifiedType and
|
||||
not arrayType.hasArraySize() and
|
||||
result = getPointerSize()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getTypeSize(Type type) {
|
||||
if exists(getTypeSizeWorkaround(type))
|
||||
then result = getTypeSizeWorkaround(type)
|
||||
else result = type.getSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRErrorType` should exist.
|
||||
*/
|
||||
predicate hasErrorType() { exists(ErroneousType t) }
|
||||
|
||||
/**
|
||||
* Holds if an `IRBooleanType` with the specified `byteSize` should exist.
|
||||
*/
|
||||
predicate hasBooleanType(int byteSize) { byteSize = getTypeSize(any(BoolType type)) }
|
||||
|
||||
private predicate isSigned(IntegralOrEnumType type) {
|
||||
type.(IntegralType).isSigned()
|
||||
or
|
||||
exists(Enum enumType |
|
||||
// If the enum has an explicit underlying type, we'll determine signedness from that. If not,
|
||||
// we'll assume unsigned. The actual rules for the implicit underlying type of an enum vary
|
||||
// between compilers, so we'll need an extractor change to get this 100% right. Until then,
|
||||
// unsigned is a reasonable default.
|
||||
enumType = type.getUnspecifiedType() and
|
||||
enumType.getExplicitUnderlyingType().getUnspecifiedType().(IntegralType).isSigned()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isSignedIntegerType(IntegralOrEnumType type) {
|
||||
isSigned(type) and not type instanceof BoolType
|
||||
}
|
||||
|
||||
private predicate isUnsignedIntegerType(IntegralOrEnumType type) {
|
||||
not isSigned(type) and not type instanceof BoolType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRSignedIntegerType` with the specified `byteSize` should exist.
|
||||
*/
|
||||
predicate hasSignedIntegerType(int byteSize) {
|
||||
byteSize = any(IntegralOrEnumType type | isSignedIntegerType(type)).getSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRUnsignedIntegerType` with the specified `byteSize` should exist.
|
||||
*/
|
||||
predicate hasUnsignedIntegerType(int byteSize) {
|
||||
byteSize = any(IntegralOrEnumType type | isUnsignedIntegerType(type)).getSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRFloatingPointType` with the specified `byteSize` should exist.
|
||||
*/
|
||||
predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() }
|
||||
|
||||
private predicate isPointerIshType(Type type) {
|
||||
type instanceof PointerType
|
||||
or
|
||||
type instanceof ReferenceType
|
||||
or
|
||||
type instanceof NullPointerType
|
||||
or
|
||||
// Treat `T[]` as a pointer. The only place we should see these is as the type of a parameter. If
|
||||
// the corresponding decayed `T*` type is available, we'll use that, but if it's not available,
|
||||
// we're stuck with `T[]`. Just treat it as a pointer.
|
||||
type instanceof ArrayType and not exists(type.getSize())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRAddressType` with the specified `byteSize` should exist.
|
||||
*/
|
||||
predicate hasAddressType(int byteSize) {
|
||||
// This covers all pointers, all references, and because it also looks at `NullPointerType`, it
|
||||
// should always return a result that makes sense for arbitrary glvalues as well.
|
||||
byteSize = any(Type type | isPointerIshType(type)).getSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRFunctionAddressType` with the specified `byteSize` should exist.
|
||||
*/
|
||||
predicate hasFunctionAddressType(int byteSize) {
|
||||
byteSize = getPointerSize() or // Covers function lvalues
|
||||
byteSize = getTypeSize(any(FunctionPointerIshType type))
|
||||
}
|
||||
|
||||
private predicate isOpaqueType(Type type) {
|
||||
exists(type.getSize()) and // Only include complete types
|
||||
(
|
||||
type instanceof ArrayType or
|
||||
type instanceof Class or
|
||||
type instanceof GNUVectorType
|
||||
)
|
||||
or
|
||||
type instanceof PointerToMemberType // PTMs are missing size info
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
||||
*/
|
||||
predicate hasOpaqueType(Type tag, int byteSize) {
|
||||
isOpaqueType(tag) and byteSize = getTypeSize(tag)
|
||||
or
|
||||
tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `IRType` that represents a prvalue of the specified `Type`.
|
||||
*/
|
||||
private IRType getIRTypeForPRValue(Type type) {
|
||||
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
||||
isOpaqueType(unspecifiedType) and
|
||||
exists(IROpaqueType opaqueType | opaqueType = result |
|
||||
opaqueType.getByteSize() = getTypeSize(type) and
|
||||
opaqueType.getTag() = unspecifiedType
|
||||
)
|
||||
or
|
||||
unspecifiedType instanceof BoolType and result.(IRBooleanType).getByteSize() = type.getSize()
|
||||
or
|
||||
isSignedIntegerType(unspecifiedType) and
|
||||
result.(IRSignedIntegerType).getByteSize() = type.getSize()
|
||||
or
|
||||
isUnsignedIntegerType(unspecifiedType) and
|
||||
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
|
||||
or
|
||||
unspecifiedType instanceof FloatingPointType and
|
||||
result.(IRFloatingPointType).getByteSize() = type.getSize()
|
||||
or
|
||||
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
|
||||
or
|
||||
unspecifiedType instanceof FunctionPointerIshType and
|
||||
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
||||
or
|
||||
unspecifiedType instanceof VoidType and result instanceof IRVoidType
|
||||
or
|
||||
unspecifiedType instanceof ErroneousType and result instanceof IRErrorType
|
||||
or
|
||||
unspecifiedType instanceof UnknownType and result instanceof IRUnknownType
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TCppType =
|
||||
TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or
|
||||
TFunctionGLValueType() or
|
||||
TGLValueAddressType(Type type) or
|
||||
TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or
|
||||
TUnknownType()
|
||||
|
||||
/**
|
||||
* The C++ type of an IR entity.
|
||||
* This cannot just be `Type` for a couple reasons:
|
||||
* - Some types needed by the IR might not exist in the database (e.g. `RoutineType`s for functions
|
||||
* that are always called directly)
|
||||
* - Some types needed by the IR are not representable in the C++ type system (e.g. the result type
|
||||
* of a `VariableAddress` where the variable is of reference type)
|
||||
*/
|
||||
class CppType extends TCppType {
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets a string used in IR dumps */
|
||||
string getDumpString() { result = toString() }
|
||||
|
||||
/** Gets the size of the type in bytes, if known. */
|
||||
final int getByteSize() { result = getIRType().getByteSize() }
|
||||
|
||||
/**
|
||||
* Gets the `IRType` that represents this `CppType`. Many different `CppType`s can map to a single
|
||||
* `IRType`.
|
||||
*/
|
||||
IRType getIRType() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the `CppType` represents a prvalue of type `Type` (if `isGLValue` is `false`), or if
|
||||
* it represents a glvalue of type `Type` (if `isGLValue` is `true`).
|
||||
*/
|
||||
predicate hasType(Type type, boolean isGLValue) { none() }
|
||||
|
||||
final predicate hasUnspecifiedType(Type type, boolean isGLValue) {
|
||||
exists(Type specifiedType |
|
||||
hasType(specifiedType, isGLValue) and
|
||||
type = specifiedType.getUnspecifiedType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CppType` that wraps an existing `Type` (either as a prvalue or a glvalue).
|
||||
*/
|
||||
private class CppWrappedType extends CppType {
|
||||
Type ctype;
|
||||
|
||||
CppWrappedType() {
|
||||
this = TPRValueType(ctype) or
|
||||
this = TGLValueAddressType(ctype)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CppType` that represents a prvalue of an existing `Type`.
|
||||
*/
|
||||
private class CppPRValueType extends CppWrappedType, TPRValueType {
|
||||
final override string toString() { result = ctype.toString() }
|
||||
|
||||
final override string getDumpString() { result = ctype.getUnspecifiedType().toString() }
|
||||
|
||||
final override IRType getIRType() { result = getIRTypeForPRValue(ctype) }
|
||||
|
||||
final override predicate hasType(Type type, boolean isGLValue) {
|
||||
type = ctype and
|
||||
isGLValue = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CppType` that has unknown type but a known size. Generally to represent synthesized types that
|
||||
* occur in certain cases during IR construction, such as the type of a zero-initialized segment of
|
||||
* a partially-initialized array.
|
||||
*/
|
||||
private class CppUnknownOpaqueType extends CppType, TUnknownOpaqueType {
|
||||
int byteSize;
|
||||
|
||||
CppUnknownOpaqueType() { this = TUnknownOpaqueType(byteSize) }
|
||||
|
||||
final override string toString() { result = "unknown[" + byteSize.toString() + "]" }
|
||||
|
||||
final override IROpaqueType getIRType() {
|
||||
result.getByteSize() = byteSize and result.getTag() instanceof UnknownType
|
||||
}
|
||||
|
||||
override predicate hasType(Type type, boolean isGLValue) {
|
||||
type instanceof UnknownType and isGLValue = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CppType` that represents a glvalue of an existing `Type`.
|
||||
*/
|
||||
private class CppGLValueAddressType extends CppWrappedType, TGLValueAddressType {
|
||||
final override string toString() { result = "glval<" + ctype.toString() + ">" }
|
||||
|
||||
final override string getDumpString() {
|
||||
result = "glval<" + ctype.getUnspecifiedType().toString() + ">"
|
||||
}
|
||||
|
||||
final override IRAddressType getIRType() { result.getByteSize() = getPointerSize() }
|
||||
|
||||
final override predicate hasType(Type type, boolean isGLValue) {
|
||||
type = ctype and
|
||||
isGLValue = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CppType` that represents a function lvalue.
|
||||
*/
|
||||
private class CppFunctionGLValueType extends CppType, TFunctionGLValueType {
|
||||
final override string toString() { result = "glval<unknown>" }
|
||||
|
||||
final override IRFunctionAddressType getIRType() { result.getByteSize() = getPointerSize() }
|
||||
|
||||
final override predicate hasType(Type type, boolean isGLValue) {
|
||||
type instanceof UnknownType and isGLValue = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CppType` that represents an unknown type.
|
||||
*/
|
||||
private class CppUnknownType extends CppType, TUnknownType {
|
||||
final override string toString() { result = any(UnknownType type).toString() }
|
||||
|
||||
final override IRUnknownType getIRType() { any() }
|
||||
|
||||
final override predicate hasType(Type type, boolean isGLValue) {
|
||||
type instanceof UnknownType and isGLValue = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single instance of `CppUnknownType`.
|
||||
*/
|
||||
CppUnknownType getUnknownType() { any() }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a prvalue of type `void`.
|
||||
*/
|
||||
CppPRValueType getVoidType() { exists(VoidType voidType | result.hasType(voidType, false)) }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a prvalue of type `type`.
|
||||
*/
|
||||
CppType getTypeForPRValue(Type type) {
|
||||
if type instanceof UnknownType
|
||||
then result instanceof CppUnknownType
|
||||
else result.hasType(type, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a prvalue of type `type`, if such a `CppType` exists.
|
||||
* Otherwise, gets `CppUnknownType`.
|
||||
*/
|
||||
CppType getTypeForPRValueOrUnknown(Type type) {
|
||||
result = getTypeForPRValue(type)
|
||||
or
|
||||
not exists(getTypeForPRValue(type)) and result = getUnknownType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a glvalue of type `type`.
|
||||
*/
|
||||
CppType getTypeForGLValue(Type type) { result.hasType(type, true) }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a prvalue of type `int`.
|
||||
*/
|
||||
CppPRValueType getIntType() {
|
||||
exists(IntType type |
|
||||
type.isImplicitlySigned() and
|
||||
result.hasType(type, false)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a prvalue of type `bool`.
|
||||
*/
|
||||
CppPRValueType getBoolType() { exists(BoolType type | result.hasType(type, false)) }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a glvalue of function type.
|
||||
*/
|
||||
CppFunctionGLValueType getFunctionGLValueType() { any() }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that represents a opaque of unknown type with size `byteSize`.
|
||||
*/
|
||||
CppUnknownOpaqueType getUnknownOpaqueType(int byteSize) { result.getByteSize() = byteSize }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRBooleanType` with the specified
|
||||
* `byteSize`.
|
||||
*/
|
||||
CppWrappedType getCanonicalBooleanType(int byteSize) {
|
||||
exists(BoolType type | result = TPRValueType(type) and byteSize = type.getSize())
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the sorting priority of an `IntegralType` based on its signedness.
|
||||
*/
|
||||
private int getSignPriority(IntegralType type) {
|
||||
// Explicitly unsigned types sort first. Explicitly signed types sort last. Types with no explicit
|
||||
// signedness sort in between. This lets us always choose `int` over `signed int`, while also
|
||||
// choosing `unsigned char`+`char` when `char` is signed, and `unsigned char`+`signed char` when
|
||||
// `char` is unsigned.
|
||||
if type.isExplicitlyUnsigned()
|
||||
then result = 2
|
||||
else
|
||||
if type.isExplicitlySigned()
|
||||
then result = 0
|
||||
else result = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sort priority of an `IntegralType` based on its kind.
|
||||
*/
|
||||
private int getKindPriority(IntegralType type) {
|
||||
// `CharType` sorts lower so that we prefer the plain integer types when they have the same size
|
||||
// as a `CharType`.
|
||||
if type instanceof CharType then result = 0 else result = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRSignedIntegerType` with the specified
|
||||
* `byteSize`.
|
||||
*/
|
||||
CppPRValueType getCanonicalSignedIntegerType(int byteSize) {
|
||||
result = TPRValueType(max(IntegralType type |
|
||||
type.isSigned() and type.getSize() = byteSize
|
||||
|
|
||||
type order by getKindPriority(type), getSignPriority(type), type.toString() desc
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRUnsignedIntegerType` with the specified
|
||||
* `byteSize`.
|
||||
*/
|
||||
CppPRValueType getCanonicalUnsignedIntegerType(int byteSize) {
|
||||
result = TPRValueType(max(IntegralType type |
|
||||
type.isUnsigned() and type.getSize() = byteSize
|
||||
|
|
||||
type order by getKindPriority(type), getSignPriority(type), type.toString() desc
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified
|
||||
* `byteSize`.
|
||||
*/
|
||||
CppPRValueType getCanonicalFloatingPointType(int byteSize) {
|
||||
result = TPRValueType(max(FloatingPointType type |
|
||||
type.getSize() = byteSize
|
||||
|
|
||||
type order by type.toString() desc
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRAddressType` with the specified
|
||||
* `byteSize`.
|
||||
*/
|
||||
CppPRValueType getCanonicalAddressType(int byteSize) {
|
||||
// We just use `NullPointerType`, since it should be unique.
|
||||
exists(NullPointerType type |
|
||||
type.getSize() = byteSize and
|
||||
result = TPRValueType(type)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRFunctionAddressType` with the specified
|
||||
* `byteSize`.
|
||||
*/
|
||||
CppFunctionGLValueType getCanonicalFunctionAddressType(int byteSize) {
|
||||
result.getByteSize() = byteSize
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for `IRErrorType`.
|
||||
*/
|
||||
CppPRValueType getCanonicalErrorType() { result = TPRValueType(any(ErroneousType type)) }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for `IRUnknownType`.
|
||||
*/
|
||||
CppUnknownType getCanonicalUnknownType() { any() }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for `IRVoidType`.
|
||||
*/
|
||||
CppPRValueType getCanonicalVoidType() { result = TPRValueType(any(VoidType type)) }
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IROpaqueType` with the specified `tag` and
|
||||
* `byteSize`.
|
||||
*/
|
||||
CppType getCanonicalOpaqueType(Type tag, int byteSize) {
|
||||
isOpaqueType(tag) and
|
||||
result = TPRValueType(tag.getUnspecifiedType()) and
|
||||
getTypeSize(tag) = byteSize
|
||||
or
|
||||
tag instanceof UnknownType and result = getUnknownOpaqueType(byteSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string that uniquely identifies an `IROpaqueType` tag. This may be different from the usual
|
||||
* `toString()` of the tag in order to ensure uniqueness.
|
||||
*/
|
||||
string getOpaqueTagIdentityString(Type tag) {
|
||||
hasOpaqueType(tag, _) and
|
||||
result = getTypeIdentityString(tag)
|
||||
}
|
||||
|
||||
module LanguageTypeSanity {
|
||||
query predicate missingCppType(Type type, string message) {
|
||||
not exists(getTypeForPRValue(type)) and
|
||||
exists(type.getSize()) and
|
||||
// `ProxyClass`es have a size, but only appear in uninstantiated templates
|
||||
not type instanceof ProxyClass and
|
||||
message = "Type does not have an associated `CppType`."
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
private import cpp as Cpp
|
||||
private import semmle.code.cpp.Print as Print
|
||||
private import IRUtilities
|
||||
private import semmle.code.cpp.ir.implementation.IRType
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
import CppType
|
||||
|
||||
class LanguageType = CppType;
|
||||
|
||||
class OpaqueTypeTag = Cpp::Type;
|
||||
|
||||
class Function = Cpp::Function;
|
||||
|
||||
|
||||
@@ -7795,16 +7795,16 @@ ir.cpp:
|
||||
# 1101| 0: [VariableAccess] x
|
||||
# 1101| Type = [IntType] int
|
||||
# 1101| ValueCategory = prvalue(load)
|
||||
# 1104| [TopLevelFunction] void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&)
|
||||
# 1104| [TopLevelFunction] void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int)
|
||||
# 1104| params:
|
||||
# 1104| 0: [Parameter] a
|
||||
# 1104| Type = [LValueReferenceType] unsigned int &
|
||||
# 1104| 1: [Parameter] b
|
||||
# 1104| Type = [LValueReferenceType] unsigned int &
|
||||
# 1104| Type = [IntType] unsigned int
|
||||
# 1104| 2: [Parameter] c
|
||||
# 1104| Type = [LValueReferenceType] unsigned int &
|
||||
# 1104| 3: [Parameter] d
|
||||
# 1104| Type = [LValueReferenceType] unsigned int &
|
||||
# 1104| Type = [IntType] unsigned int
|
||||
# 1105| body: [Block] { ... }
|
||||
# 1106| 0: [AsmStmt] asm statement
|
||||
# 1109| 0: [ReferenceDereferenceExpr] (reference dereference)
|
||||
@@ -7813,24 +7813,18 @@ ir.cpp:
|
||||
# 1109| expr: [VariableAccess] a
|
||||
# 1109| Type = [LValueReferenceType] unsigned int &
|
||||
# 1109| ValueCategory = prvalue(load)
|
||||
# 1109| 1: [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1109| 1: [VariableAccess] b
|
||||
# 1109| Type = [IntType] unsigned int
|
||||
# 1109| ValueCategory = lvalue
|
||||
# 1109| expr: [VariableAccess] b
|
||||
# 1109| Type = [LValueReferenceType] unsigned int &
|
||||
# 1109| ValueCategory = prvalue(load)
|
||||
# 1109| 2: [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1109| Type = [IntType] unsigned int
|
||||
# 1109| ValueCategory = lvalue
|
||||
# 1109| ValueCategory = prvalue(load)
|
||||
# 1109| expr: [VariableAccess] c
|
||||
# 1109| Type = [LValueReferenceType] unsigned int &
|
||||
# 1109| ValueCategory = prvalue(load)
|
||||
# 1109| 3: [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1109| 3: [VariableAccess] d
|
||||
# 1109| Type = [IntType] unsigned int
|
||||
# 1109| ValueCategory = lvalue
|
||||
# 1109| expr: [VariableAccess] d
|
||||
# 1109| Type = [LValueReferenceType] unsigned int &
|
||||
# 1109| ValueCategory = prvalue(load)
|
||||
# 1109| ValueCategory = prvalue(load)
|
||||
# 1111| 1: [ReturnStmt] return ...
|
||||
# 1113| [TopLevelFunction] void ExternDeclarations()
|
||||
# 1113| params:
|
||||
|
||||
@@ -14,3 +14,8 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -1101,12 +1101,12 @@ int AsmStmt(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
static void AsmStmtWithOutputs(unsigned int& a, unsigned int& b, unsigned int& c, unsigned int& d)
|
||||
static void AsmStmtWithOutputs(unsigned int& a, unsigned int b, unsigned int& c, unsigned int d)
|
||||
{
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"cpuid\n\t"
|
||||
: "+a" (a), "+b" (b), "+c" (c), "+d" (d)
|
||||
: "+a" (a), "+b" (b) : "c" (c), "d" (d)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2194,24 +2194,24 @@ ir.cpp:
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 489| Block 1
|
||||
# 489| r1_0(glval<int>) = VariableAddress[#temp489:6] :
|
||||
# 489| r1_1(glval<int>) = Load : &:r1_0, ~mu0_2
|
||||
# 489| mu1_2(int) = Store : &:r1_1, r0_9
|
||||
# 490| v1_3(void) = NoOp :
|
||||
# 486| v1_4(void) = ReturnVoid :
|
||||
# 486| v1_5(void) = UnmodeledUse : mu*
|
||||
# 486| v1_6(void) = ExitFunction :
|
||||
# 489| r1_0(glval<unknown>) = VariableAddress[#temp489:6] :
|
||||
# 489| r1_1(glval<int>) = Load : &:r1_0, ~mu0_2
|
||||
# 489| mu1_2(int) = Store : &:r1_1, r0_9
|
||||
# 490| v1_3(void) = NoOp :
|
||||
# 486| v1_4(void) = ReturnVoid :
|
||||
# 486| v1_5(void) = UnmodeledUse : mu*
|
||||
# 486| v1_6(void) = ExitFunction :
|
||||
|
||||
# 489| Block 2
|
||||
# 489| r2_0(glval<int>) = VariableAddress[x] :
|
||||
# 489| r2_1(glval<int>) = VariableAddress[#temp489:6] :
|
||||
# 489| mu2_2(int) = Store : &:r2_1, r2_0
|
||||
# 489| r2_0(glval<int>) = VariableAddress[x] :
|
||||
# 489| r2_1(glval<unknown>) = VariableAddress[#temp489:6] :
|
||||
# 489| mu2_2(glval<int>) = Store : &:r2_1, r2_0
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 489| Block 3
|
||||
# 489| r3_0(glval<int>) = VariableAddress[y] :
|
||||
# 489| r3_1(glval<int>) = VariableAddress[#temp489:6] :
|
||||
# 489| mu3_2(int) = Store : &:r3_1, r3_0
|
||||
# 489| r3_0(glval<int>) = VariableAddress[y] :
|
||||
# 489| r3_1(glval<unknown>) = VariableAddress[#temp489:6] :
|
||||
# 489| mu3_2(glval<int>) = Store : &:r3_1, r3_0
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 492| void Conditional_Void(bool)
|
||||
@@ -2690,12 +2690,12 @@ ir.cpp:
|
||||
# 590| mu0_1(unknown) = AliasedDefinition :
|
||||
# 590| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 591| r0_3(glval<..(*)(..)>) = VariableAddress[pfn] :
|
||||
# 591| r0_4(glval<..(*)(..)>) = FunctionAddress[FuncPtrTarget] :
|
||||
# 591| r0_4(..(*)(..)) = FunctionAddress[FuncPtrTarget] :
|
||||
# 591| mu0_5(..(*)(..)) = Store : &:r0_3, r0_4
|
||||
# 592| r0_6(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] :
|
||||
# 592| r0_7(glval<..(*)(..)>) = VariableAddress[pfn] :
|
||||
# 592| mu0_8(..(*)(..)) = Store : &:r0_7, r0_6
|
||||
# 593| r0_9(glval<..(*)(..)>) = FunctionAddress[FuncPtrTarget] :
|
||||
# 593| r0_9(..(*)(..)) = FunctionAddress[FuncPtrTarget] :
|
||||
# 593| r0_10(glval<..(*)(..)>) = VariableAddress[pfn] :
|
||||
# 593| mu0_11(..(*)(..)) = Store : &:r0_10, r0_9
|
||||
# 594| r0_12(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] :
|
||||
@@ -4637,7 +4637,7 @@ ir.cpp:
|
||||
# 1029| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1029| r0_3(glval<decltype([...](...){...})>) = InitializeThis :
|
||||
# 1029| r0_4(glval<..(*)(..)>) = VariableAddress[#return] :
|
||||
# 1029| r0_5(glval<..(*)(..)>) = FunctionAddress[_FUN] :
|
||||
# 1029| r0_5(..(*)(..)) = FunctionAddress[_FUN] :
|
||||
# 1029| mu0_6(..(*)(..)) = Store : &:r0_4, r0_5
|
||||
# 1029| r0_7(glval<..(*)(..)>) = VariableAddress[#return] :
|
||||
# 1029| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2
|
||||
@@ -4840,7 +4840,7 @@ ir.cpp:
|
||||
# 1032| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1032| r0_3(glval<decltype([...](...){...})>) = InitializeThis :
|
||||
# 1032| r0_4(glval<..(*)(..)>) = VariableAddress[#return] :
|
||||
# 1032| r0_5(glval<..(*)(..)>) = FunctionAddress[_FUN] :
|
||||
# 1032| r0_5(..(*)(..)) = FunctionAddress[_FUN] :
|
||||
# 1032| mu0_6(..(*)(..)) = Store : &:r0_4, r0_5
|
||||
# 1032| r0_7(glval<..(*)(..)>) = VariableAddress[#return] :
|
||||
# 1032| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2
|
||||
@@ -5240,28 +5240,32 @@ ir.cpp:
|
||||
# 1099| v0_12(void) = UnmodeledUse : mu*
|
||||
# 1099| v0_13(void) = ExitFunction :
|
||||
|
||||
# 1104| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&)
|
||||
# 1104| void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int)
|
||||
# 1104| Block 0
|
||||
# 1104| v0_0(void) = EnterFunction :
|
||||
# 1104| mu0_1(unknown) = AliasedDefinition :
|
||||
# 1104| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1104| r0_3(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 1104| mu0_4(unsigned int &) = InitializeParameter[a] : &:r0_3
|
||||
# 1104| r0_5(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 1104| mu0_6(unsigned int &) = InitializeParameter[b] : &:r0_5
|
||||
# 1104| r0_5(glval<unsigned int>) = VariableAddress[b] :
|
||||
# 1104| mu0_6(unsigned int) = InitializeParameter[b] : &:r0_5
|
||||
# 1104| r0_7(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 1104| mu0_8(unsigned int &) = InitializeParameter[c] : &:r0_7
|
||||
# 1104| r0_9(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 1104| mu0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
|
||||
# 1106| r0_11(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 1106| r0_12(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 1106| r0_13(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 1106| r0_14(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 1106| mu0_15(unknown) = InlineAsm : ~mu0_2, 0:r0_11, 1:r0_12, 2:r0_13, 3:r0_14
|
||||
# 1111| v0_16(void) = NoOp :
|
||||
# 1104| v0_17(void) = ReturnVoid :
|
||||
# 1104| v0_18(void) = UnmodeledUse : mu*
|
||||
# 1104| v0_19(void) = ExitFunction :
|
||||
# 1104| r0_9(glval<unsigned int>) = VariableAddress[d] :
|
||||
# 1104| mu0_10(unsigned int) = InitializeParameter[d] : &:r0_9
|
||||
# 1109| r0_11(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 1109| r0_12(unsigned int &) = Load : &:r0_11, ~mu0_2
|
||||
# 1109| r0_13(glval<unsigned int>) = VariableAddress[b] :
|
||||
# 1109| r0_14(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 1109| r0_15(unsigned int &) = Load : &:r0_14, ~mu0_2
|
||||
# 1109| r0_16(unsigned int) = Load : &:r0_15, ~mu0_2
|
||||
# 1109| r0_17(glval<unsigned int>) = VariableAddress[d] :
|
||||
# 1109| r0_18(unsigned int) = Load : &:r0_17, ~mu0_2
|
||||
# 1106| mu0_19(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_13, 2:r0_16, 3:r0_18
|
||||
# 1111| v0_20(void) = NoOp :
|
||||
# 1104| v0_21(void) = ReturnVoid :
|
||||
# 1104| v0_22(void) = UnmodeledUse : mu*
|
||||
# 1104| v0_23(void) = ExitFunction :
|
||||
|
||||
# 1113| void ExternDeclarations()
|
||||
# 1113| Block 0
|
||||
|
||||
@@ -14,3 +14,8 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -14,3 +14,8 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -747,26 +747,28 @@ ssa.cpp:
|
||||
# 184| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 184| r0_3(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 184| m0_4(unsigned int &) = InitializeParameter[a] : &:r0_3
|
||||
# 184| m0_5(unknown) = Chi : total:m0_1, partial:m0_4
|
||||
# 184| r0_6(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 184| m0_7(unsigned int &) = InitializeParameter[b] : &:r0_6
|
||||
# 184| m0_8(unknown) = Chi : total:m0_5, partial:m0_7
|
||||
# 184| r0_9(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 184| m0_10(unsigned int &) = InitializeParameter[c] : &:r0_9
|
||||
# 184| m0_11(unknown) = Chi : total:m0_8, partial:m0_10
|
||||
# 184| r0_12(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 184| m0_13(unsigned int &) = InitializeParameter[d] : &:r0_12
|
||||
# 184| m0_14(unknown) = Chi : total:m0_11, partial:m0_13
|
||||
# 186| r0_15(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 186| r0_16(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 186| r0_17(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 186| r0_18(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 186| m0_19(unknown) = InlineAsm : ~mu0_2, 0:r0_15, 1:r0_16, 2:r0_17, 3:r0_18
|
||||
# 186| m0_20(unknown) = Chi : total:m0_14, partial:m0_19
|
||||
# 192| v0_21(void) = NoOp :
|
||||
# 184| v0_22(void) = ReturnVoid :
|
||||
# 184| v0_23(void) = UnmodeledUse : mu*
|
||||
# 184| v0_24(void) = ExitFunction :
|
||||
# 184| r0_5(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 184| m0_6(unsigned int &) = InitializeParameter[b] : &:r0_5
|
||||
# 184| r0_7(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 184| m0_8(unsigned int &) = InitializeParameter[c] : &:r0_7
|
||||
# 184| r0_9(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 184| m0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
|
||||
# 189| r0_11(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 189| r0_12(unsigned int &) = Load : &:r0_11, m0_4
|
||||
# 189| r0_13(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 189| r0_14(unsigned int &) = Load : &:r0_13, m0_6
|
||||
# 190| r0_15(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 190| r0_16(unsigned int &) = Load : &:r0_15, m0_8
|
||||
# 190| r0_17(unsigned int) = Load : &:r0_16, ~m0_1
|
||||
# 190| r0_18(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 190| r0_19(unsigned int &) = Load : &:r0_18, m0_10
|
||||
# 190| r0_20(unsigned int) = Load : &:r0_19, ~m0_1
|
||||
# 186| m0_21(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_14, 2:r0_17, 3:r0_20
|
||||
# 186| m0_22(unknown) = Chi : total:m0_1, partial:m0_21
|
||||
# 192| v0_23(void) = NoOp :
|
||||
# 184| v0_24(void) = ReturnVoid :
|
||||
# 184| v0_25(void) = UnmodeledUse : mu*
|
||||
# 184| v0_26(void) = ExitFunction :
|
||||
|
||||
# 198| int PureFunctions(char*, char*, int)
|
||||
# 198| Block 0
|
||||
|
||||
@@ -14,3 +14,8 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -714,22 +714,28 @@ ssa.cpp:
|
||||
# 184| mu0_1(unknown) = AliasedDefinition :
|
||||
# 184| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 184| r0_3(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 184| mu0_4(unsigned int &) = InitializeParameter[a] : &:r0_3
|
||||
# 184| m0_4(unsigned int &) = InitializeParameter[a] : &:r0_3
|
||||
# 184| r0_5(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 184| mu0_6(unsigned int &) = InitializeParameter[b] : &:r0_5
|
||||
# 184| m0_6(unsigned int &) = InitializeParameter[b] : &:r0_5
|
||||
# 184| r0_7(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 184| mu0_8(unsigned int &) = InitializeParameter[c] : &:r0_7
|
||||
# 184| m0_8(unsigned int &) = InitializeParameter[c] : &:r0_7
|
||||
# 184| r0_9(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 184| mu0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
|
||||
# 186| r0_11(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 186| r0_12(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 186| r0_13(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 186| r0_14(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 186| mu0_15(unknown) = InlineAsm : ~mu0_2, 0:r0_11, 1:r0_12, 2:r0_13, 3:r0_14
|
||||
# 192| v0_16(void) = NoOp :
|
||||
# 184| v0_17(void) = ReturnVoid :
|
||||
# 184| v0_18(void) = UnmodeledUse : mu*
|
||||
# 184| v0_19(void) = ExitFunction :
|
||||
# 184| m0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
|
||||
# 189| r0_11(glval<unsigned int &>) = VariableAddress[a] :
|
||||
# 189| r0_12(unsigned int &) = Load : &:r0_11, m0_4
|
||||
# 189| r0_13(glval<unsigned int &>) = VariableAddress[b] :
|
||||
# 189| r0_14(unsigned int &) = Load : &:r0_13, m0_6
|
||||
# 190| r0_15(glval<unsigned int &>) = VariableAddress[c] :
|
||||
# 190| r0_16(unsigned int &) = Load : &:r0_15, m0_8
|
||||
# 190| r0_17(unsigned int) = Load : &:r0_16, ~mu0_2
|
||||
# 190| r0_18(glval<unsigned int &>) = VariableAddress[d] :
|
||||
# 190| r0_19(unsigned int &) = Load : &:r0_18, m0_10
|
||||
# 190| r0_20(unsigned int) = Load : &:r0_19, ~mu0_2
|
||||
# 186| mu0_21(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_14, 2:r0_17, 3:r0_20
|
||||
# 192| v0_22(void) = NoOp :
|
||||
# 184| v0_23(void) = ReturnVoid :
|
||||
# 184| v0_24(void) = UnmodeledUse : mu*
|
||||
# 184| v0_25(void) = ExitFunction :
|
||||
|
||||
# 198| int PureFunctions(char*, char*, int)
|
||||
# 198| Block 0
|
||||
|
||||
@@ -14,3 +14,8 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -13,7 +13,6 @@ missingOperandType
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| VacuousDestructorCall.cpp:2:29:2:29 | InitializeParameter: y |
|
||||
| assume0.cpp:7:2:7:2 | Chi: call to f |
|
||||
| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt |
|
||||
| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt |
|
||||
| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt |
|
||||
@@ -546,3 +545,8 @@ lostReachability
|
||||
| range_analysis.c:371:37:371:39 | Constant: 500 |
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -8,6 +8,7 @@ missingOperand
|
||||
| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
|
||||
| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
|
||||
| pointer_to_member.cpp:36:13:36:19 | FieldAddress: x1 | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
|
||||
| pointer_to_member.cpp:36:22:36:28 | Store: f1 | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
|
||||
| range_analysis.c:368:10:368:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
|
||||
| range_analysis.c:369:10:369:36 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
|
||||
| range_analysis.c:370:10:370:38 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
|
||||
@@ -25,8 +26,6 @@ instructionWithoutSuccessor
|
||||
| VacuousDestructorCall.cpp:2:29:2:29 | InitializeParameter: y |
|
||||
| VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x |
|
||||
| VacuousDestructorCall.cpp:4:3:4:3 | Load: y |
|
||||
| assume0.cpp:7:2:7:2 | CallSideEffect: call to f |
|
||||
| assume0.cpp:9:11:9:11 | Constant: (bool)... |
|
||||
| condition_decls.cpp:16:19:16:20 | CallSideEffect: call to BoxedInt |
|
||||
| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi |
|
||||
| condition_decls.cpp:26:23:26:24 | CallSideEffect: call to BoxedInt |
|
||||
@@ -46,7 +45,6 @@ instructionWithoutSuccessor
|
||||
| misc.c:219:47:219:48 | InitializeParameter: sp |
|
||||
| misc.c:221:10:221:10 | Store: 1 |
|
||||
| misc.c:222:10:222:10 | Store: 2 |
|
||||
| ms_assume.cpp:20:12:20:12 | Constant: (bool)... |
|
||||
| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x |
|
||||
| ms_try_except.cpp:7:13:7:17 | Store: ... = ... |
|
||||
| ms_try_except.cpp:9:19:9:19 | Load: j |
|
||||
@@ -68,6 +66,7 @@ instructionWithoutSuccessor
|
||||
| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... |
|
||||
| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } |
|
||||
| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} |
|
||||
| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} |
|
||||
| static_init_templates.cpp:80:27:80:36 | Convert: (void *)... |
|
||||
| static_init_templates.cpp:80:27:80:36 | Convert: (void *)... |
|
||||
| static_init_templates.cpp:89:27:89:36 | Convert: (void *)... |
|
||||
@@ -612,7 +611,6 @@ lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
| VacuousDestructorCall.cpp:4:3:4:3 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | IR: CallDestructor | void CallDestructor<int>(int, int*) |
|
||||
| assume0.cpp:11:2:11:2 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | assume0.cpp:5:6:5:6 | IR: h | void h() |
|
||||
| condition_decls.cpp:16:15:16:15 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) |
|
||||
| condition_decls.cpp:16:15:16:16 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) |
|
||||
| condition_decls.cpp:16:15:16:16 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) |
|
||||
@@ -681,6 +679,7 @@ useNotDominatedByDefinition
|
||||
| ms_try_mix.cpp:51:5:51:11 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:47:6:47:28 | IR: ms_empty_finally_at_end | void ms_empty_finally_at_end() |
|
||||
| pointer_to_member.cpp:36:11:36:30 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
|
||||
| pointer_to_member.cpp:36:13:36:19 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
|
||||
| pointer_to_member.cpp:36:22:36:28 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
|
||||
| stmt_expr.cpp:30:20:30:21 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) |
|
||||
| stmt_expr.cpp:31:16:31:18 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) |
|
||||
| try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) |
|
||||
@@ -694,3 +693,8 @@ useNotDominatedByDefinition
|
||||
| vla.c:14:40:14:45 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | vla.c:11:6:11:16 | IR: vla_typedef | void vla_typedef() |
|
||||
| vla.c:14:58:14:63 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | vla.c:11:6:11:16 | IR: vla_typedef | void vla_typedef() |
|
||||
| vla.c:14:74:14:79 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | vla.c:11:6:11:16 | IR: vla_typedef | void vla_typedef() |
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -22,7 +22,6 @@ missingOperandType
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| VacuousDestructorCall.cpp:2:29:2:29 | InitializeParameter: y |
|
||||
| assume0.cpp:7:2:7:2 | CallSideEffect: call to f |
|
||||
| condition_decls.cpp:16:19:16:20 | CallSideEffect: call to BoxedInt |
|
||||
| condition_decls.cpp:26:23:26:24 | CallSideEffect: call to BoxedInt |
|
||||
| condition_decls.cpp:41:22:41:23 | CallSideEffect: call to BoxedInt |
|
||||
@@ -555,3 +554,8 @@ lostReachability
|
||||
| range_analysis.c:371:37:371:39 | Constant: 500 |
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -394,27 +394,27 @@ test.cpp:
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 56| Block 3
|
||||
# 56| m3_0(char *) = Phi : from 2:m2_3, from 5:m5_4
|
||||
# 56| m3_0(decltype(nullptr)) = Phi : from 2:m2_3, from 5:m5_4
|
||||
# 56| valnum = m3_0
|
||||
# 56| r3_1(glval<char *>) = VariableAddress[ptr] :
|
||||
# 56| r3_1(glval<char *>) = VariableAddress[ptr] :
|
||||
# 56| valnum = r0_7
|
||||
# 56| r3_2(char *) = Load : &:r3_1, m3_0
|
||||
# 56| r3_2(char *) = Load : &:r3_1, m3_0
|
||||
# 56| valnum = m3_0
|
||||
# 56| r3_3(char) = Load : &:r3_2, ~m0_1
|
||||
# 56| r3_3(char) = Load : &:r3_2, ~m0_1
|
||||
# 56| valnum = unique
|
||||
# 56| r3_4(int) = Convert : r3_3
|
||||
# 56| r3_4(int) = Convert : r3_3
|
||||
# 56| valnum = unique
|
||||
# 56| r3_5(glval<char *>) = VariableAddress[str] :
|
||||
# 56| r3_5(glval<char *>) = VariableAddress[str] :
|
||||
# 56| valnum = r0_3
|
||||
# 56| r3_6(char *) = Load : &:r3_5, m0_4
|
||||
# 56| r3_6(char *) = Load : &:r3_5, m0_4
|
||||
# 56| valnum = m0_4
|
||||
# 56| r3_7(char) = Load : &:r3_6, ~m0_1
|
||||
# 56| r3_7(char) = Load : &:r3_6, ~m0_1
|
||||
# 56| valnum = unique
|
||||
# 56| r3_8(int) = Convert : r3_7
|
||||
# 56| r3_8(int) = Convert : r3_7
|
||||
# 56| valnum = unique
|
||||
# 56| r3_9(bool) = CompareNE : r3_4, r3_8
|
||||
# 56| r3_9(bool) = CompareNE : r3_4, r3_8
|
||||
# 56| valnum = unique
|
||||
# 56| v3_10(void) = ConditionalBranch : r3_9
|
||||
# 56| v3_10(void) = ConditionalBranch : r3_9
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 4
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
| ..()(..) | RoutineType | | | | |
|
||||
| ..(*)(..) | FunctionPointerType | | ..()(..) | | |
|
||||
| _Complex __float128 | ArithmeticType | | | | |
|
||||
| _Complex __float128 | FloatingPointType | | | | |
|
||||
| _Complex double | FloatingPointType | | | | |
|
||||
| _Complex float | FloatingPointType | | | | |
|
||||
| _Complex long double | FloatingPointType | | | | |
|
||||
| _Decimal32 | ArithmeticType | | | | |
|
||||
| _Decimal64 | ArithmeticType | | | | |
|
||||
| _Decimal128 | ArithmeticType | | | | |
|
||||
| _Float32 | ArithmeticType | | | | |
|
||||
| _Float32x | ArithmeticType | | | | |
|
||||
| _Float64 | ArithmeticType | | | | |
|
||||
| _Float64x | ArithmeticType | | | | |
|
||||
| _Float128 | ArithmeticType | | | | |
|
||||
| _Float128x | ArithmeticType | | | | |
|
||||
| _Decimal32 | Decimal32Type | | | | |
|
||||
| _Decimal64 | Decimal64Type | | | | |
|
||||
| _Decimal128 | Decimal128Type | | | | |
|
||||
| _Float32 | FloatingPointType | | | | |
|
||||
| _Float32x | FloatingPointType | | | | |
|
||||
| _Float64 | FloatingPointType | | | | |
|
||||
| _Float64x | FloatingPointType | | | | |
|
||||
| _Float128 | FloatingPointType | | | | |
|
||||
| _Float128x | FloatingPointType | | | | |
|
||||
| _Imaginary double | FloatingPointType | | | | |
|
||||
| _Imaginary float | FloatingPointType | | | | |
|
||||
| _Imaginary long double | FloatingPointType | | | | |
|
||||
|
||||
Reference in New Issue
Block a user