C#: Add calli IL opcode extraction

This commit is contained in:
Tamas Vajk
2021-02-11 18:10:43 +01:00
parent 17109a36ce
commit f2e667173c
7 changed files with 78 additions and 31 deletions

View File

@@ -128,6 +128,11 @@ namespace Semmle.Extraction.CIL
case HandleKind.TypeDefinition:
entity = new TypeDefinitionType(this, (TypeDefinitionHandle)handle);
break;
case HandleKind.StandaloneSignature:
var signature = MdReader.GetStandaloneSignature((StandaloneSignatureHandle)handle);
var method = signature.DecodeMethodSignature(gc.Cx.TypeSignatureDecoder, gc);
entity = new FunctionPointerType(this, method);
break;
default:
throw new InternalError("Unhandled handle kind " + handle.Kind);
}

View File

@@ -385,19 +385,21 @@ namespace Semmle.Extraction.CIL.Entities
case Payload.Type:
case Payload.Field:
case Payload.ValueType:
// A generic EntityHandle.
var handle = MetadataTokens.EntityHandle(payloadValue);
var target = Cx.CreateGeneric(Method, handle);
yield return target;
if (target != null)
{
yield return Tuples.cil_access(this, target);
// A generic EntityHandle.
var handle = MetadataTokens.EntityHandle(payloadValue);
var target = Cx.CreateGeneric(Method, handle);
yield return target;
if (target != null)
{
yield return Tuples.cil_access(this, target);
}
else
{
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
}
break;
}
else
{
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
}
break;
case Payload.Arg8:
case Payload.Arg16:
if (Method.Parameters is object)
@@ -417,10 +419,33 @@ namespace Semmle.Extraction.CIL.Entities
case Payload.Target32:
case Payload.Switch:
case Payload.Ignore8:
case Payload.CallSiteDesc:
// These are not handled here.
// Some of these are handled by JumpContents().
break;
case Payload.CallSiteDesc:
{
var handle = MetadataTokens.EntityHandle(payloadValue);
IExtractedEntity? target = null;
try
{
target = Cx.CreateGeneric(Method, handle);
}
catch (Exception exc)
{
Cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}");
}
if (target != null)
{
yield return target;
yield return Tuples.cil_access(this, target);
}
else
{
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
}
break;
}
default:
throw new InternalError($"Unhandled payload type {PayloadType}");
}

View File

@@ -79,7 +79,13 @@ class MissingValue extends InstructionViolation {
* A call that does not have exactly one `getTarget()`.
*/
class MissingCallTarget extends InstructionViolation {
MissingCallTarget() { exists(Call c | c = instruction | count(c.getTarget()) != 1) }
MissingCallTarget() {
exists(Call c | c = instruction |
count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli
or
count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli
)
}
override string getMessage() { result = "Call has invalid target" }
}

View File

@@ -482,6 +482,22 @@ module Opcodes {
override string getOpcodeName() { result = "call" }
}
/** A `calli` instruction. */
class Calli extends Call, @cil_calli {
override string getOpcodeName() { result = "calli" }
override Callable getTarget() { none() }
/** Gets the function pointer type targetted by this instruction. */
FunctionPointerType getTargetType() { cil_access(this, result) }
// The number of items popped/pushed from the stack depends on the target of
// the call. Also, we need to pop the function pointer itself too.
override int getPopCount() { result = getTargetType().getCallPopCount() + 1 }
override int getPushCount() { result = getTargetType().getCallPushCount() }
}
/** A `callvirt` instruction. */
class Callvirt extends Call, @cil_callvirt {
override string getOpcodeName() { result = "callvirt" }

View File

@@ -310,4 +310,15 @@ class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable,
int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) }
override string toString() { result = Type.super.toString() }
/** Holds if the return type is `void`. */
predicate returnsVoid() { getReturnType() instanceof VoidType }
/** Gets the number of stack items pushed in a call to this method. */
int getCallPushCount() { if returnsVoid() then result = 0 else result = 1 }
/** Gets the number of stack items popped in a call to this method. */
int getCallPopCount() { result = count(getRawParameter(_)) }
override string getLabel() { result = getName() }
}

View File

@@ -902,6 +902,8 @@ class FunctionPointerType extends Type, Parameterizable, @function_pointer_type
AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) }
override string getAPrimaryQlClass() { result = "FunctionPointerType" }
override string getLabel() { result = getName() }
}
/**

View File

@@ -1,19 +1 @@
| DispatchTailCalls | No label |
| EnumCalendarInfo | No label |
| Finalize | Overridden method from System.Object is not in a base type |
| Unknown instruction in DispatchTailCalls | Call has invalid target |
| Unknown instruction in DispatchTailCalls | Cfg node has 0 pop counts |
| Unknown instruction in DispatchTailCalls | Cfg node has 0 push counts |
| Unknown instruction in DispatchTailCalls | Inconsistent stack size |
| Unknown instruction in DispatchTailCalls | Opcode 41 is missing a QL class |
| bne.un.s | Inconsistent stack size |
| conv.u | Inconsistent stack size |
| delegate* managed<IntPtr,IntPtr,IntPtr*,Void> | No label |
| delegate* unmanaged<Char*,IntPtr,Void> | No label |
| ldarg.1 | Inconsistent stack size |
| ldc.i4.0 | Inconsistent stack size |
| ldfld | Inconsistent stack size |
| ldloc.3 | Inconsistent stack size |
| leave.s | Inconsistent stack size |
| ret | Inconsistent stack size |
| starg.s | Inconsistent stack size |