diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 19202f5d49c..053b018eaf5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -7,7 +7,9 @@ private import internal.IRTypeInternal newtype TIRType = TIRVoidType() or TIRUnknownType() or - TIRErrorType() or + TIRErrorType() { + Language::hasErrorType() + } or TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -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 @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { 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`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll index 0138af075dc..a75f70dbe2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -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 @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { 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`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll index 0138af075dc..a75f70dbe2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -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 @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { 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`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll index 0138af075dc..a75f70dbe2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index 5af6b402ee3..9fa6ebe5018 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -31,6 +31,13 @@ private int getTypeSize(Type 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. */ @@ -170,9 +177,7 @@ private newtype TCppType = * of a `VariableAddress` where the variable is of reference type) */ class CppType extends TCppType { - string toString() { - result = "" - } + abstract string toString(); /** Gets a string used in IR dumps */ string getDumpString() { result = toString() } @@ -191,6 +196,13 @@ class CppType extends TCppType { * it represents a glvalue of type `Type` (if `isGLValue` is `true`). */ abstract predicate hasType(Type type, boolean isGLValue); + + final predicate hasUnspecifiedType(Type type, boolean isGLValue) { + exists(Type specifiedType | + hasType(specifiedType, isGLValue) and + type = specifiedType.getUnspecifiedType() + ) + } } /** @@ -204,6 +216,7 @@ private class CppWrappedType extends CppType { this = TGLValueAddressType(ctype) } + abstract string toString(); abstract override IRType getIRType(); abstract override predicate hasType(Type type, boolean isGLValue); } diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql index be1474d7b1c..d2368e7bf4a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql +++ b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql @@ -1,7 +1,7 @@ /** * @name Print IR * @description Outputs a representation of the IR graph - * @id charp/print-ir + * @id csharp/print-ir * @kind graph */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll new file mode 100644 index 00000000000..163d384c759 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -0,0 +1,259 @@ +/** + * 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 + TIRBlobType(Language::BlobTypeTag tag, int byteSize) { + Language::hasBlobType(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 { + abstract string toString(); + + /** + * 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`. + */ + abstract int getByteSize(); + + /** + * Gets a single instance of `LanguageType` that maps to this `IRType`. + */ + abstract Language::LanguageType getCanonicalLanguageType(); +} + +/** + * 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 = TIRBlobType(_, byteSize) + } + + abstract override string toString(); + + final override int getByteSize() { result = byteSize } + + abstract override Language::LanguageType getCanonicalLanguageType(); +} + +/** + * 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) + } + + abstract override string toString(); + + abstract override Language::LanguageType getCanonicalLanguageType(); +} + +/** + * 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 IRBlobType extends IRSizedType, TIRBlobType { + Language::BlobTypeTag tag; + + IRBlobType() { + this = TIRBlobType(tag, byteSize) + } + + final override string toString() { + result = "blob" + byteSize.toString() + "{" + tag.toString() + "}" + } + + final override string getIdentityString() { + result = "blob" + byteSize.toString() + "{" + Language::getBlobTagIdentityString(tag) + "}" + } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalBlobType(tag, byteSize) + } + + /** + * Gets the "tag" that differentiates this type from other incompatible blob types that have the + * same size. + */ + final Language::BlobTypeTag 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(), ", ") + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll new file mode 100644 index 00000000000..0ee01a30ac3 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll @@ -0,0 +1 @@ +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -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 @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { 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`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll index 372f5383db0..b26327d9248 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,8 @@ import csharp import semmle.code.csharp.ir.implementation.raw.IR private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType +private import semmle.code.csharp.ir.internal.Overlap private import semmle.code.csharp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -31,16 +33,18 @@ private module Cached { cached newtype TInstruction = MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _, _) + element.hasInstruction(_, tag, _) } cached - predicate hasUserVariable(Callable callable, Variable var, Type type) { + predicate hasUserVariable(Callable callable, Variable var, CSharpType type) { getTranslatedFunction(callable).hasUserVariable(var, type) } cached - predicate hasTempVariable(Callable callable, Language::AST ast, TempVariableTag tag, Type type) { + predicate hasTempVariable( + Callable callable, Language::AST ast, TempVariableTag tag, CSharpType type + ) { exists(TranslatedElement element | element.getAST() = ast and callable = element.getFunction() and @@ -83,22 +87,16 @@ private module Cached { } cached - Type getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { + CSharpType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as // the result type of the load. if instruction instanceof LoadInstruction - then result = instruction.(LoadInstruction).getResultType() + then result = instruction.(LoadInstruction).getResultLanguageType() else 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 @@ -216,15 +214,15 @@ private module Cached { } cached - predicate instructionHasType(Instruction instruction, Type type, boolean isLValue) { + CSharpType getInstructionResultType(Instruction instruction) { getInstructionTranslatedElement(instruction) - .hasInstruction(_, getInstructionTag(instruction), type, isLValue) + .hasInstruction(_, getInstructionTag(instruction), result) } cached Opcode getInstructionOpcode(Instruction instruction) { getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _, _) + .hasInstruction(result, getInstructionTag(instruction), _) } cached @@ -271,7 +269,7 @@ private module Cached { } cached - Type getInstructionExceptionType(Instruction instruction) { + CSharpType getInstructionExceptionType(Instruction instruction) { result = getInstructionTranslatedElement(instruction) .getInstructionExceptionType(getInstructionTag(instruction)) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll index b5abc1049f3..3b716c201ac 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll @@ -1,2 +1,3 @@ import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll index 20c299416ef..9ab8de41259 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll @@ -1,3 +1,4 @@ +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll index da9b8e6e877..8628f5be373 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll @@ -1,4 +1,5 @@ import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.csharp.ir.implementation.Opcode as Opcode import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll index 13667df7276..19e753f8a4a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll @@ -1,3 +1,4 @@ +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.csharp.ir.internal.Overlap as Overlap import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll index 93e8e67200a..85106cfbf27 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll @@ -1,6 +1,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr @@ -34,7 +35,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -100,7 +101,7 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 879ac4d1384..85af08a411f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -3,6 +3,7 @@ import semmle.code.csharp.ir.implementation.raw.IR private import semmle.code.csharp.ir.IRConfiguration private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -15,11 +16,6 @@ private import desugar.Foreach private import desugar.Delegate private import desugar.Lock -/** - * Gets the built-in `int` type. - */ -IntType getIntType() { any() } - ArrayType getArrayOfDim(int dim, Type type) { result.getRank() = dim and result.getElementType() = type @@ -411,7 +407,7 @@ abstract class TranslatedElement extends TTranslatedElement { * `VoidType`. */ abstract predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ); /** @@ -452,7 +448,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, CSharpType type) { none() } /** * If the instruction specified by `tag` is a `FunctionInstruction`, gets the @@ -507,7 +503,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() } + CSharpType getInstructionExceptionType(InstructionTag tag) { none() } /** * If the instruction specified by `tag` is an `InheritanceConversionInstruction`, @@ -526,13 +522,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() } - - /** - * Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`. - * Only holds for operands whose type is `UnknownType`. - */ - int getInstructionOperandSize(InstructionTag tag, SideEffectOperandTag operandTag) { none() } + CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } /** * Gets the instruction generated by this element with tag `tag`. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 8e83de3e027..4cea9e9f8f2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -2,6 +2,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag private import semmle.code.csharp.ir.internal.TempVariableTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRUtilities private import InstructionTag private import TranslatedCondition @@ -96,6 +97,12 @@ abstract class TranslatedCoreExpr extends TranslatedExpr { not needsLoad(expr) } + final CSharpType getResultCSharpType() { + if isResultLValue() = true + then result = getTypeForGLValue(expr.getType()) + else result = getTypeForPRValue(expr.getType()) + } + /** * Returns `true` if the result of this `TranslatedExpr` is a lvalue, or * `false` if the result is a rvalue. @@ -118,7 +125,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( tag = ConditionValueTrueTempAddressTag() or @@ -126,29 +133,25 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, tag = ConditionValueResultTempAddressTag() ) and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) or ( tag = ConditionValueTrueConstantTag() or tag = ConditionValueFalseConstantTag() ) and opcode instanceof Opcode::Constant and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() or ( tag = ConditionValueTrueStoreTag() or tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -209,9 +212,9 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ConditionValueTempVar() and - type = this.getResultType() + type = this.getResultCSharpType() } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -260,12 +263,13 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = expr.getType() and - if not this.producesExprResult() then isLValue = true else isLValue = false + if producesExprResult() + then resultType = getTypeForPRValue(expr.getType()) + else resultType = getTypeForGLValue(expr.getType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -326,32 +330,29 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { or resultType instanceof FloatingPointType and result = this.getResultType() or - resultType instanceof PointerType and result = getIntType() + resultType instanceof PointerType and result = any(IntType t) ) ) } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - isLValue = false and - ( - tag = CrementLoadTag() and - opcode instanceof Opcode::Load and - resultType = this.getResultType() - or - tag = CrementConstantTag() and - opcode instanceof Opcode::Constant and - resultType = this.getConstantType() - or - tag = CrementOpTag() and - opcode = this.getOpcode() and - resultType = this.getResultType() - or - tag = CrementStoreTag() and - opcode instanceof Opcode::Store and - resultType = this.getResultType() - ) + tag = CrementLoadTag() and + opcode instanceof Opcode::Load and + resultType = getTypeForPRValue(expr.getType()) + or + tag = CrementConstantTag() and + opcode instanceof Opcode::Constant and + resultType = getTypeForPRValue(this.getConstantType()) + or + tag = CrementOpTag() and + opcode = this.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) { @@ -467,7 +468,7 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -506,7 +507,7 @@ class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, Initial override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -609,22 +610,20 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { override Instruction getResult() { result = this.getInstruction(PointerAddTag(getRank() - 1)) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { exists(int index | inBounds(index) and tag = PointerAddTag(index) and opcode instanceof Opcode::PointerAdd and - resultType = this.getInstruction(ElementsAddressTag(index)).getResultType() and - isLValue = false + resultType = getTypeForPRValue(getArrayOfDim(getRank() - index, expr.getType())) ) or exists(int index | inBounds(index) and tag = ElementsAddressTag(index) and opcode instanceof Opcode::ElementsAddress and - resultType = getArrayOfDim(getRank() - index, expr.getType()) and - isLValue = false + resultType = getTypeForPRValue(getArrayOfDim(getRank() - index, expr.getType())) ) } @@ -694,7 +693,7 @@ abstract class TranslatedPointerOps extends TranslatedNonConstantExpr { } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -726,12 +725,11 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { final override TranslatedElement getChild(int id) { none() } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::CopyValue and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } @@ -778,13 +776,12 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { this.needsExtraLoad() and tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -856,14 +853,13 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType, isLValue) + TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType) or tag = AddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(this.getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -902,12 +898,11 @@ class TranslatedFieldAccess extends TranslatedVariableAccess { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = AddressTag() and opcode instanceof Opcode::FieldAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) } override Field getInstructionField(InstructionTag tag) { @@ -932,12 +927,11 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::FunctionAddress and - resultType = expr.getType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) } override Callable getInstructionFunction(InstructionTag tag) { @@ -982,12 +976,11 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode = this.getOpcode() and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -1034,12 +1027,11 @@ abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr abstract Opcode getOpcode(); final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { opcode = getOpcode() and tag = OnlyInstructionTag() and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() } final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } @@ -1112,13 +1104,12 @@ class TranslatedCast extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( tag = ConvertTag() and opcode = this.getOpcode() and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) ) } @@ -1289,7 +1280,7 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( this.needsConversion() and @@ -1298,8 +1289,7 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr { // crudely represent conversions. Could // be useful to represent the whole chain of conversions opcode instanceof Opcode::Convert and - resultType = expr.getLValue().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getLValue().getType()) ) } @@ -1347,14 +1337,13 @@ class TranslatedAssignExpr extends TranslatedAssignment { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - TranslatedAssignment.super.hasInstruction(opcode, tag, resultType, isLValue) + TranslatedAssignment.super.hasInstruction(opcode, tag, resultType) or tag = AssignmentStoreTag() and opcode instanceof Opcode::Store and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1472,31 +1461,28 @@ class TranslatedAssignOperation extends TranslatedAssignment { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - isLValue = false and + tag = AssignOperationLoadTag() and + opcode instanceof Opcode::Load and + resultType = getTypeForPRValue(this.getLeftOperand().getResultType()) + or + tag = AssignOperationOpTag() and + opcode = getOpcode() and + resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) + or + tag = AssignmentStoreTag() and + opcode instanceof Opcode::Store and + resultType = getTypeForPRValue(expr.getType()) + or + this.leftOperandNeedsConversion() and + opcode instanceof Opcode::Convert and ( - tag = AssignOperationLoadTag() and - opcode instanceof Opcode::Load and - resultType = this.getLeftOperand().getResultType() + tag = AssignOperationConvertLeftTag() and + resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) or - tag = AssignOperationOpTag() and - opcode = getOpcode() and - resultType = this.getConvertedLeftOperandType() - or - tag = AssignmentStoreTag() and - opcode instanceof Opcode::Store and - resultType = this.getResultType() - or - this.leftOperandNeedsConversion() and - opcode instanceof Opcode::Convert and - ( - tag = AssignOperationConvertLeftTag() and - resultType = this.getConvertedLeftOperandType() - or - tag = AssignOperationConvertResultTag() and - resultType = this.getLeftOperand().getResultType() - ) + tag = AssignOperationConvertResultTag() and + resultType = getTypeForPRValue(this.getLeftOperand().getResultType()) ) } @@ -1583,7 +1569,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { not this.resultIsVoid() and ( @@ -1595,8 +1581,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont tag = ConditionValueResultTempAddressTag() ) and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(this.getResultType()) or ( not this.thenIsVoid() and tag = ConditionValueTrueStoreTag() @@ -1604,13 +1589,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont not this.elseIsVoid() and tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(this.getResultType()) or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = this.getResultCSharpType() ) } @@ -1678,10 +1661,10 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { not this.resultIsVoid() and tag = ConditionValueTempVar() and - type = this.getResultType() + type = getTypeForPRValue(this.getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -1816,34 +1799,29 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { this.hasVar() and tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = expr.getPattern().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getPattern().getType()) or tag = ConvertTag() and opcode instanceof Opcode::CheckedConvertOrNull and - resultType = expr.getPattern().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getPattern().getType()) or tag = GeneratedNEQTag() and opcode instanceof Opcode::CompareNE and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) or tag = GeneratedConstantTag() and opcode instanceof Opcode::Constant and - resultType = expr.getPattern().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getPattern().getType()) or this.hasVar() and tag = GeneratedBranchTag() and opcode instanceof Opcode::ConditionalBranch and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } override string getInstructionConstantValue(InstructionTag tag) { @@ -1932,22 +1910,19 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) or tag = InitializerStoreTag() and opcode instanceof Opcode::Uninitialized and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) or tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1973,9 +1948,9 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont result = this.getTempVariable(LambdaTempVar()) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LambdaTempVar() and - type = this.getResultType() + type = getTypeForPRValue(this.getResultType()) } final override Instruction getTargetAddress() { @@ -2015,7 +1990,7 @@ class TranslatedDelegateCall extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -2044,20 +2019,18 @@ abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreatio } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { // Instruction that allocated space for a new object, // and returns its address tag = NewObjTag() and opcode instanceof Opcode::NewObj and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) or this.needsLoad() and tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index 41f88e25766..00fb956f30c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -1,6 +1,7 @@ import csharp import semmle.code.csharp.ir.implementation.raw.IR private import semmle.code.csharp.ir.implementation.Opcode +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRUtilities private import semmle.code.csharp.ir.implementation.internal.OperandTag private import semmle.code.csharp.ir.internal.TempVariableTag @@ -121,39 +122,33 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( tag = EnterFunctionTag() and opcode instanceof Opcode::EnterFunction and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() or tag = UnmodeledDefinitionTag() and opcode instanceof Opcode::UnmodeledDefinition and - resultType instanceof Language::UnknownType and - isLValue = false + resultType = getUnknownType() or tag = AliasedDefinitionTag() and opcode instanceof Opcode::AliasedDefinition and - resultType instanceof Language::UnknownType and - isLValue = false + resultType = getUnknownType() or tag = InitializeThisTag() and opcode instanceof Opcode::InitializeThis and - resultType = getThisType() and - isLValue = true + resultType = getTypeForGLValue(getThisType()) or tag = ReturnValueAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getReturnType() and - not resultType instanceof VoidType and - isLValue = true + not getReturnType() instanceof VoidType and + resultType = getTypeForGLValue(getReturnType()) or ( tag = ReturnTag() and - resultType instanceof VoidType and - isLValue = false and + resultType = getVoidType() and if this.getReturnType() instanceof VoidType then opcode instanceof Opcode::ReturnVoid else opcode instanceof Opcode::ReturnValue @@ -161,8 +156,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or tag = UnwindTag() and opcode instanceof Opcode::Unwind and - resultType instanceof VoidType and - isLValue = false and + resultType = getVoidType() and ( // Only generate the `Unwind` instruction if there is any exception // handling present in the function (compiler generated or not). @@ -172,13 +166,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or tag = UnmodeledUseTag() and opcode instanceof Opcode::UnmodeledUse and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() or tag = ExitFunctionTag() and opcode instanceof Opcode::ExitFunction and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() ) } @@ -207,11 +199,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { ) } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = ReturnTag() and not this.getReturnType() instanceof VoidType and operandTag instanceof LoadOperandTag and - result = this.getReturnType() + result = getTypeForPRValue(this.getReturnType()) } final override IRVariable getInstructionVariable(InstructionTag tag) { @@ -219,10 +211,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = this.getReturnVariable() } - final override predicate hasTempVariable(TempVariableTag tag, Type type) { + final override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ReturnValueTempVar() and - type = this.getReturnType() and - not type instanceof VoidType + type = getTypeForPRValue(this.getReturnType()) and + not getReturnType() instanceof VoidType } /** @@ -278,7 +270,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { * parameters and local variables, plus any static fields that are directly accessed by the * function. */ - final predicate hasUserVariable(Variable var, Type type) { + final predicate hasUserVariable(Variable var, CSharpType type) { ( var.(Member).isStatic() and exists(VariableAccess access | @@ -288,7 +280,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or var.(LocalScopeVariable).getCallable() = callable ) and - type = getVariableType(var) + type = getTypeForPRValue(getVariableType(var)) } final private Type getReturnType() { result = callable.getReturnType() } @@ -334,17 +326,15 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter { final override Instruction getChildSuccessor(TranslatedElement child) { none() } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getVariableType(param) and - isLValue = true + resultType = getTypeForGLValue(param.getType()) or tag = InitializerStoreTag() and opcode instanceof Opcode::InitializeParameter and - resultType = getVariableType(param) and - isLValue = false + resultType = getTypeForPRValue(param.getType()) } final override IRVariable getInstructionVariable(InstructionTag tag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll index d0d98a4918a..35dea9ab94b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -6,6 +6,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr @@ -88,7 +89,7 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -135,12 +136,11 @@ class TranslatedDirectInitialization extends TranslatedInitialization { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = this.getContext().getTargetType() and - isLValue = false + resultType = getTypeForPRValue(this.getContext().getTargetType()) or needsConversion() and tag = AssignmentConvertRightTag() and @@ -148,8 +148,7 @@ class TranslatedDirectInitialization extends TranslatedInitialization { // crudely represent conversions. Could // be useful to represent the whole chain of conversions opcode instanceof Opcode::Convert and - resultType = this.getContext().getTargetType() and - isLValue = false + resultType = getTypeForPRValue(this.getContext().getTargetType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -219,17 +218,15 @@ abstract class TranslatedElementInitialization extends TranslatedElement { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = getElementIndexTag() and opcode instanceof Opcode::Constant and - resultType = getIntType() and - isLValue = false + resultType = getIntType() or tag = getElementAddressTag() and opcode instanceof Opcode::PointerAdd and - resultType = getElementType() and - isLValue = true + resultType = getTypeForGLValue(getElementType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -354,13 +351,12 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { this.needsConversion() and tag = OnlyInstructionTag() and opcode instanceof Opcode::Convert and - resultType = call.getTarget().getDeclaringType() and - isLValue = true + resultType = getTypeForGLValue(call.getTarget().getDeclaringType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll index 3e4934987a3..20590c133b0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1,4 +1,5 @@ import csharp +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.internal.OperandTag private import InstructionTag @@ -40,12 +41,11 @@ class TranslatedEmptyStmt extends TranslatedStmt { override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -63,7 +63,7 @@ class TranslatedDeclStmt extends TranslatedStmt { override TranslatedElement getChild(int id) { result = this.getLocalDeclaration(id) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -98,7 +98,7 @@ class TranslatedExprStmt extends TranslatedStmt { override TranslatedElement getChild(int id) { id = 0 and result = this.getExpr() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -162,12 +162,11 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getEnclosingFunction().getReturnVariable().getType() and - isLValue = true + resultType = getTypeForGLValue(this.getEnclosingFunction().getFunction().getReturnType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -207,12 +206,11 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt { override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -241,7 +239,7 @@ class TranslatedTryStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -290,13 +288,12 @@ class TranslatedBlock extends TranslatedStmt { override TranslatedElement getChild(int id) { result = this.getStmt(id) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { isEmpty() and opcode instanceof Opcode::NoOp and tag = OnlyInstructionTag() and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getFirstInstruction() { @@ -358,12 +355,11 @@ class TranslatedCatchByTypeClause extends TranslatedClause { TranslatedCatchByTypeClause() { stmt instanceof SpecificCatchClause } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = CatchTag() and opcode instanceof Opcode::CatchByType and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override TranslatedElement getChild(int id) { @@ -389,9 +385,9 @@ class TranslatedCatchByTypeClause extends TranslatedClause { ) } - override Type getInstructionExceptionType(InstructionTag tag) { + override CSharpType getInstructionExceptionType(InstructionTag tag) { tag = CatchTag() and - result = stmt.(SpecificCatchClause).getVariable().getType() + result = getTypeForPRValue(stmt.(SpecificCatchClause).getVariable().getType()) } private TranslatedLocalDeclaration getParameter() { @@ -406,12 +402,11 @@ class TranslatedGeneralCatchClause extends TranslatedClause { TranslatedGeneralCatchClause() { stmt instanceof GeneralCatchClause } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = CatchTag() and opcode instanceof Opcode::CatchAny and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -440,17 +435,15 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = ThrowTag() and opcode instanceof Opcode::ThrowValue and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() or tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getExceptionType() and - isLValue = true + resultType = getTypeForGLValue(this.getExceptionType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -473,9 +466,9 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext result = getIRTempVariable(stmt, ThrowTempVar()) } - final override predicate hasTempVariable(TempVariableTag tag, Type type) { + final override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ThrowTempVar() and - type = this.getExceptionType() + type = getTypeForPRValue(this.getExceptionType()) } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -490,10 +483,10 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext ) } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = ThrowTag() and operandTag instanceof LoadOperandTag and - result = this.getExceptionType() + result = getTypeForPRValue(this.getExceptionType()) } override Instruction getTargetAddress() { @@ -523,12 +516,11 @@ class TranslatedEmptyThrowStmt extends TranslatedStmt { override Instruction getFirstInstruction() { result = this.getInstruction(ThrowTag()) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = ThrowTag() and opcode instanceof Opcode::ReThrow and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -583,7 +575,7 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -611,7 +603,7 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -725,12 +717,11 @@ abstract class TranslatedSpecificJump extends TranslatedStmt { override TranslatedElement getChild(int id) { none() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -853,12 +844,11 @@ class TranslatedSwitchStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = SwitchBranchTag() and opcode instanceof Opcode::Switch and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -936,7 +926,7 @@ class TranslatedUnsafeStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -972,7 +962,7 @@ class TranslatedFixedStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1013,7 +1003,7 @@ class TranslatedLockStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1047,7 +1037,7 @@ class TranslatedCheckedUncheckedStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1090,7 +1080,7 @@ class TranslatedUsingBlockStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1126,7 +1116,7 @@ class TranslatedUsingDeclStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll index b6f708d04d9..9a0edd85456 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll @@ -10,6 +10,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.Util +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language private import TranslatedExprBase @@ -33,12 +34,11 @@ abstract class TranslatedCallBase extends TranslatedElement { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = CallTag() and opcode instanceof Opcode::Call and - resultType = getCallResultType() and - isLValue = false + resultType = getTypeForPRValue(getCallResultType()) or hasSideEffect() and tag = CallSideEffectTag() and @@ -46,20 +46,18 @@ abstract class TranslatedCallBase extends TranslatedElement { if hasWriteSideEffect() then ( opcode instanceof Opcode::CallSideEffect and - resultType instanceof Language::UnknownType + resultType = getUnknownType() ) else ( opcode instanceof Opcode::CallReadSideEffect and - resultType instanceof Language::UnknownType + resultType = getUnknownType() ) - ) and - isLValue = false + ) or tag = CallTargetTag() and opcode instanceof Opcode::FunctionAddress and // Since the DB does not have a function type, // we just use the UnknownType - resultType instanceof Language::UnknownType and - isLValue = true + resultType = getFunctionAddressType() } override Instruction getChildSuccessor(TranslatedElement child) { @@ -115,11 +113,11 @@ abstract class TranslatedCallBase extends TranslatedElement { result = getUnmodeledDefinitionInstruction() } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = CallSideEffectTag() and hasSideEffect() and operandTag instanceof SideEffectOperandTag and - result instanceof Language::UnknownType + result = getUnknownType() } Instruction getResult() { result = getInstruction(CallTag()) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll index 7503e3b41e2..5252cdac863 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll @@ -9,6 +9,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language /** @@ -39,12 +40,11 @@ abstract class ValueConditionBase extends ConditionBase { override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = ValueConditionConditionalBranchTag() and opcode instanceof Opcode::ConditionalBranch and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getChildSuccessor(TranslatedElement child) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll index fbf5db28ec8..88a8961bf66 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll @@ -11,6 +11,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language abstract class LocalVariableDeclarationBase extends TranslatedElement { @@ -19,18 +20,16 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement { override Instruction getFirstInstruction() { result = getVarAddress() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getVarType() and - isLValue = true + resultType = getTypeForGLValue(getVarType()) or hasUninitializedInstruction() and tag = InitializerStoreTag() and opcode instanceof Opcode::Uninitialized and - resultType = getVarType() and - isLValue = false + resultType = getTypeForPRValue(getVarType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll index 1b29ac7c543..33697848155 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll @@ -8,6 +8,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction @@ -31,7 +32,7 @@ abstract class TranslatedCompilerGeneratedTry extends TranslatedCompilerGenerate override Stmt generatedBy; override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -73,12 +74,11 @@ abstract class TranslatedCompilerGeneratedTry extends TranslatedCompilerGenerate */ abstract class TranslatedCompilerGeneratedConstant extends TranslatedCompilerGeneratedExpr { override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { opcode instanceof Opcode::Constant and tag = OnlyInstructionTag() and - resultType = getResultType() and - isLValue = false + resultType = getTypeForPRValue(getResultType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -118,7 +118,7 @@ abstract class TranslatedCompilerGeneratedBlock extends TranslatedCompilerGenera } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -171,7 +171,7 @@ abstract class TranslatedCompilerGeneratedIfStmt extends TranslatedCompilerGener } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -191,18 +191,16 @@ abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompi override Instruction getChildSuccessor(TranslatedElement child) { none() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = AddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getResultType() and - isLValue = true + resultType = getTypeForGLValue(getResultType()) or needsLoad() and tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() and - isLValue = false + resultType = getTypeForPRValue(getResultType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll index 06a001e8912..a7b1881e92b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll @@ -36,6 +36,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr @@ -113,7 +114,7 @@ class TranslatedForeachWhile extends TranslatedCompilerGeneratedStmt, ConditionC TranslatedForeachWhile() { this = TTranslatedCompilerGeneratedElement(generatedBy, 2) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -329,9 +330,9 @@ private class TranslatedForeachEnumerator extends TranslatedCompilerGeneratedDec TranslatedForeachEnumerator() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getInitialization().getCallResultType() + type = getTypeForPRValue(getInitialization().getCallResultType()) } override IRTempVariable getIRVariable() { @@ -388,9 +389,9 @@ private class TranslatedMoveNextEnumAcc extends TTranslatedCompilerGeneratedElem override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -413,9 +414,9 @@ private class TranslatedForeachCurrentEnumAcc extends TTranslatedCompilerGenerat override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -438,9 +439,9 @@ private class TranslatedForeachDisposeEnumAcc extends TTranslatedCompilerGenerat override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll index 1fb0167b4cc..7a0ec9d5cbc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll @@ -21,6 +21,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement @@ -259,9 +260,9 @@ private class TranslatedLockWasTakenDecl extends TranslatedCompilerGeneratedDecl TranslatedLockWasTakenDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockWasTakenTemp() and - type instanceof BoolType + type = getBoolType() } override IRTempVariable getIRVariable() { @@ -290,9 +291,9 @@ private class TranslatedLockedVarDecl extends TranslatedCompilerGeneratedDeclara TranslatedLockedVarDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 9) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockedVarTemp() and - type = generatedBy.getExpr().getType() + type = getTypeForPRValue(generatedBy.getExpr().getType()) } override IRTempVariable getIRVariable() { @@ -321,9 +322,9 @@ private class TranslatedMonitorEnterVarAcc extends TTranslatedCompilerGeneratedE override Type getResultType() { result = generatedBy.getExpr().getType() } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockedVarTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -352,9 +353,9 @@ private class TranslatedMonitorExitVarAcc extends TTranslatedCompilerGeneratedEl result = getTempVariable(LockedVarTemp()) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockedVarTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override predicate needsLoad() { any() } @@ -372,9 +373,9 @@ private class TranslatedLockWasTakenCondVarAcc extends TTranslatedCompilerGenera override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockWasTakenTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -397,9 +398,9 @@ private class TranslatedLockWasTakenRefArg extends TTranslatedCompilerGeneratedE override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockWasTakenTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll index 5820a8b8309..2fac4b38999 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll @@ -12,6 +12,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedEleme private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedDeclarationBase private import TranslatedCompilerGeneratedElement +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase, @@ -29,17 +30,16 @@ abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDecla } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - LocalVariableDeclarationBase.super.hasInstruction(opcode, tag, resultType, isLValue) + LocalVariableDeclarationBase.super.hasInstruction(opcode, tag, resultType) or // we can reuse the initializer store tag // since compiler generated declarations // do not have the `Uninitialized` instruction tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = getVarType() and - isLValue = false + resultType = getTypeForPRValue(getVarType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll new file mode 100644 index 00000000000..cf0ae13a426 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll @@ -0,0 +1,424 @@ +private import csharp +private import semmle.code.csharp.ir.implementation.IRType +private import IRCSharpLanguage as Language + +int getTypeSize(Type type) { + // REVIEW: Is this complete? + result = type.(SimpleType).getSize() + or + result = getTypeSize(type.(Enum).getUnderlyingType()) + or + // TODO: Generate a reasonable size + type instanceof Struct and result = 16 + or + type instanceof RefType and result = getPointerSize() + or + type instanceof PointerType and result = getPointerSize() + or + result = getTypeSize(type.(TupleType).getUnderlyingType()) + or + // TODO: Add room for extra field + result = getTypeSize(type.(NullableType).getUnderlyingType()) + or + type instanceof VoidType and result = 0 +} + +int getPointerSize() { + result = 8 +} + +/** + * Holds if an `IRErrorType` should exist. + */ +predicate hasErrorType() { + exists(UnknownType t) +} + +/** + * Holds if an `IRBooleanType` with the specified `byteSize` should exist. + */ +predicate hasBooleanType(int byteSize) { + byteSize = getTypeSize(any(BoolType type)) +} + +private predicate isSignedIntegerType(ValueType type) { + type instanceof SignedIntegralType or + type.(Enum).getUnderlyingType() instanceof SignedIntegralType +} + +private predicate isUnsignedIntegerType(ValueType type) { + type instanceof UnsignedIntegralType or + type instanceof CharType or + type.(Enum).getUnderlyingType() instanceof UnsignedIntegralType +} + +/** + * Holds if an `IRSignedIntegerType` with the specified `byteSize` should exist. + */ +predicate hasSignedIntegerType(int byteSize) { + byteSize = getTypeSize(any(ValueType type | isSignedIntegerType(type))) +} + +/** + * Holds if an `IRUnsignedIntegerType` with the specified `byteSize` should exist. + */ +predicate hasUnsignedIntegerType(int byteSize) { + byteSize = getTypeSize(any(ValueType type | isUnsignedIntegerType(type))) +} + +/** + * 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 RefType +} + +/** + * 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 `NullType`, it + // should always return a result that makes sense for arbitrary glvalues as well. + byteSize = getTypeSize(any(Type type | isPointerIshType(type))) +} + +/** + * Holds if an `IRFunctionAddressType` with the specified `byteSize` should exist. + */ +predicate hasFunctionAddressType(int byteSize) { + byteSize = getTypeSize(any(NullType type)) +} + +private int getBaseClassSize(ValueOrRefType type) { + if exists(type.getBaseClass()) + then result = getContentSize(type.getBaseClass()) + else result = 0 +} + +private int getContentSize(ValueOrRefType type) { + result = getBaseClassSize(type) + + sum(Field field | + not field.isStatic() | + getTypeSize(field.getType()) + ) +} + +private predicate isBlobType(ValueOrRefType type) { + type instanceof Struct or + type instanceof NullableType or + type instanceof DecimalType +} + +/** + * Holds if an `IRBlobType` with the specified `tag` and `byteSize` should exist. + */ +predicate hasBlobType(Type tag, int byteSize) { + isBlobType(tag) and byteSize = getTypeSize(tag) +} + +private Type getRepresentationType(Type type) { + result = type.(Enum).getUnderlyingType() + or + result = type.(TupleType).getUnderlyingType() + or + not type instanceof Enum and not type instanceof TupleType and result = type +} + +/** + * Gets the `IRType` that represents a prvalue of the specified `Type`. + */ +private IRType getIRTypeForPRValue(Type type) { + exists(Type repType | + repType = getRepresentationType(type) | + exists(IRBlobType blobType | + blobType = result | + blobType.getByteSize() = getTypeSize(repType) and + blobType.getTag() = repType + ) + or + result.(IRBooleanType).getByteSize() = repType.(BoolType).getSize() + or + isSignedIntegerType(repType) and + result.(IRSignedIntegerType).getByteSize() = getTypeSize(repType) + or + isUnsignedIntegerType(repType) and + result.(IRUnsignedIntegerType).getByteSize() = getTypeSize(repType) + or + result.(IRFloatingPointType).getByteSize() = repType.(FloatingPointType).getSize() + or + isPointerIshType(repType) and result.(IRAddressType).getByteSize() = getTypeSize(repType) + or + repType instanceof VoidType and result instanceof IRVoidType + or + repType instanceof UnknownType and result instanceof IRErrorType + ) +} + +string getBlobTagIdentityString(Type tag) { + result = tag.getQualifiedName() +} + +private newtype TCSharpType = + TPRValueType(Type type) { + exists(getIRTypeForPRValue(type)) + } or + TGLValueAddressType(Type type) { + any() + } or + TFunctionAddressType() or + TUnknownType() + +class CSharpType extends TCSharpType { + abstract string toString(); + + /** 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 `CSharpType`. Many different `CSharpType`s can map to a + * single `IRType`. + */ + abstract IRType getIRType(); + + /** + * Holds if the `CSharpType` represents a prvalue of type `Type` (if `isGLValue` is `false`), or + * if it represents a glvalue of type `Type` (if `isGLValue` is `true`). + */ + abstract predicate hasType(Type type, boolean isGLValue); + + final predicate hasUnspecifiedType(Type type, boolean isGLValue) { + hasType(type, isGLValue) + } +} + +/** + * A `CSharpType` that wraps an existing `Type` (either as a prvalue or a glvalue). + */ +private class CSharpWrappedType extends CSharpType { + Type cstype; + + CSharpWrappedType() { + this = TPRValueType(cstype) or + this = TGLValueAddressType(cstype) + } + + abstract override string toString(); + abstract override IRType getIRType(); + abstract override predicate hasType(Type type, boolean isGLValue); +} + +/** + * A `CSharpType` that represents a prvalue of an existing `Type`. + */ +private class CSharpPRValueType extends CSharpWrappedType, TPRValueType { + override final string toString() { result = cstype.toString() } + + override final IRType getIRType() { result = getIRTypeForPRValue(cstype) } + + override final predicate hasType(Type type, boolean isGLValue) { + type = cstype and + isGLValue = false + } +} + +/** + * A `CSharpType` that represents a glvalue of an existing `Type`. + */ +private class CSharpGLValueAddressType extends CSharpWrappedType, TGLValueAddressType { + override final string toString() { + result = "glval<" + cstype.toString() + ">" + } + + override final IRAddressType getIRType() { + result.getByteSize() = getPointerSize() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type = cstype and + isGLValue = true + } +} + +/** + * A `CSharpType` that represents a function address. + */ +private class CSharpFunctionAddressType extends CSharpType, TFunctionAddressType { + override final string toString() { +// result = "" // FIXME + result = "glval" + } + + override final IRFunctionAddressType getIRType() { + result.getByteSize() = getPointerSize() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type instanceof VoidType and isGLValue = true + } +} + +/** + * A `CSharpType` that represents an unknown type. + */ +private class CSharpUnknownType extends CSharpType, TUnknownType { + override final string toString() { +// result = "" // FIXME + result = "null" + } + + override final IRUnknownType getIRType() { + any() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type instanceof VoidType and isGLValue = false + } +} + +/** + * Gets the single instance of `CSharpUnknownType`. + */ +CSharpUnknownType getUnknownType() { + any() +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `void`. + */ +CSharpPRValueType getVoidType() { + exists(VoidType voidType | + result.hasType(voidType, false) + ) +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `type`. + */ +CSharpPRValueType getTypeForPRValue(Type type) { + result.hasType(type, false) +} + +/** + * Gets the `CSharpType` that represents a glvalue of type `type`. + */ +CSharpGLValueAddressType getTypeForGLValue(Type type) { + result.hasType(type, true) +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `int`. + */ +CSharpPRValueType getIntType() { + result.hasType(any(IntType t), false) +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `bool`. + */ +CSharpPRValueType getBoolType() { + result.hasType(any(BoolType t), false) +} + +/** + * Gets the `CSharpType` that represents a prvalue of `NullType`. + */ +CSharpPRValueType getNullType() { + result.hasType(any(NullType t), false) +} + +/** + * Gets the `CSharpType` that represents a function address. + */ +CSharpFunctionAddressType getFunctionAddressType() { + any() +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRBooleanType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalBooleanType(int byteSize) { + exists(BoolType type | + result = TPRValueType(type) and byteSize = type.getSize() + ) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRSignedIntegerType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalSignedIntegerType(int byteSize) { + result = TPRValueType(any(SignedIntegralType t | t.getSize() = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRUnsignedIntegerType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalUnsignedIntegerType(int byteSize) { + result = TPRValueType(any(UnsignedIntegralType t | t.getSize() = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRFloatingPointType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalFloatingPointType(int byteSize) { + result = TPRValueType(any(FloatingPointType type | type.getSize() = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRAddressType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalAddressType(int byteSize) { + // We just use `NullType`, since it should be unique. + result = TPRValueType(any(NullType type | getTypeSize(type) = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRFunctionAddressType` with the specified + * `byteSize`. + */ +CSharpFunctionAddressType getCanonicalFunctionAddressType(int byteSize) { + result.getByteSize() = byteSize +} + +/** + * Gets the `CSharpType` that is the canonical type for `IRErrorType`. + */ +CSharpPRValueType getCanonicalErrorType() { + result = TPRValueType(any(UnknownType type)) +} + +/** + * Gets the `CSharpType` that is the canonical type for `IRUnknownType`. + */ +CSharpUnknownType getCanonicalUnknownType() { + any() +} + +/** + * Gets the `CSharpType` that is the canonical type for `IRVoidType`. + */ +CSharpPRValueType getCanonicalVoidType() { + result = TPRValueType(any(VoidType type)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRBlobType` with the specified `tag` and + * `byteSize`. + */ +CSharpPRValueType getCanonicalBlobType(Type tag, int byteSize) { + isBlobType(tag) and + result = TPRValueType(tag) and + getTypeSize(tag) = byteSize +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll index c359879c87f..5ff50b8f825 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll @@ -1,5 +1,9 @@ private import csharp as CSharp private import IRUtilities +import CSharpType + +class LanguageType = CSharpType; +class BlobTypeTag = CSharp::ValueOrRefType; class Function = CSharp::Callable; @@ -81,32 +85,6 @@ predicate hasPositionalArgIndex(int argIndex) { predicate hasAsmOperandIndex(int operandIndex) { none() } -int getTypeSize(Type type) { - // REVIEW: Is this complete? - result = type.(CSharp::SimpleType).getSize() - or - result = getTypeSize(type.(CSharp::Enum).getUnderlyingType()) - or - // TODO: Generate a reasonable size - type instanceof CSharp::Struct and result = 16 - or - type instanceof CSharp::RefType and result = getPointerSize() - or - type instanceof CSharp::PointerType and result = getPointerSize() - or - result = getTypeSize(type.(CSharp::TupleType).getUnderlyingType()) - or - // TODO: Add room for extra field - result = getTypeSize(type.(CSharp::NullableType).getUnderlyingType()) - or - type instanceof CSharp::VoidType and result = 0 -} - -int getPointerSize() { - // TODO: Deal with sizes in general - result = 8 -} - predicate isVariableAutomatic(Variable var) { var instanceof CSharp::LocalScopeVariable } string getStringLiteralText(StringLiteral s) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll index c14e361aa01..1aeace91377 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll @@ -1,25 +1,13 @@ private import csharp /** - * Get the actual type of the specified variable, as opposed to the declared type. - * This returns the type of the variable after any pointer decay is applied, and - * after any unsized array type has its size inferred from the initializer. + * Get the actual type of the specified variable, as opposed to the declared + * type. */ Type getVariableType(Variable v) { - exists(Type declaredType | - declaredType = v.getType() and - if v instanceof Parameter - then result = declaredType - else - if declaredType instanceof ArrayType - then - // TODO: Arrays have a declared dimension in C#, so this should not be needed - // and not declaredType.(ArrayType).hasArraySize() - result = v.getInitializer().getType() - or - not exists(v.getInitializer()) and result = declaredType - else result = declaredType - ) + // C# doesn't seem to have any cases where the variable's actual type differs + // from its declared type. + result = v.getType() } predicate hasCaseEdge(CaseStmt caseStmt, string minValue, string maxValue) { diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes