mirror of
https://github.com/github/codeql.git
synced 2025-12-24 12:46:34 +01:00
C#: Implement IRType
This commit implements the language-neutral IR type system for C#. It mostly follows the same pattern as C++, modified to fit the C# type system. All object references, pointers, and lvalues are represented as `IRAddress` types. All structs and generic parameters are implemented as `IRBlobType`. Function addresses get a single `IRFunctionAddressType`. I had to fix a couple places in the original IR type system where I didn't realize I was still depending on language-specific types. As part of this, `CSharpType` and `CppType` now have a `hasUnspecifiedType()` predicate, which is equivalent to `hasType()`, except that it holds only for the unspecified version of the type. This predicate can go away once we remove the IR's references to the underlying `Type` objects. All C# IR tests pass without modification, but only because this commit continues to print the name of `IRUnknownType` as `null`, and `IRFunctionAddressType` as `glval<null>`. These will be fixed separately in a subsequent commit in this PR.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user