mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
C#: Add calli IL opcode extraction
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 |
|
||||
|
||||
Reference in New Issue
Block a user