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:
Dave Bartolomeo
2019-09-26 15:47:52 -07:00
parent 300e580874
commit e30e163081
34 changed files with 1018 additions and 385 deletions

View File

@@ -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

View File

@@ -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
)
)
}

View File

@@ -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

View File

@@ -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
)
)
}

View File

@@ -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

View File

@@ -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
)
)
}

View File

@@ -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

View File

@@ -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);
}