Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f2e6671

Browse files
committed
C#: Add calli IL opcode extraction
1 parent 17109a3 commit f2e6671

7 files changed

Lines changed: 78 additions & 31 deletions

File tree

csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ private IExtractedEntity CreateGenericHandle(IGenericContext gc, Handle handle)
128128
case HandleKind.TypeDefinition:
129129
entity = new TypeDefinitionType(this, (TypeDefinitionHandle)handle);
130130
break;
131+
case HandleKind.StandaloneSignature:
132+
var signature = MdReader.GetStandaloneSignature((StandaloneSignatureHandle)handle);
133+
var method = signature.DecodeMethodSignature(gc.Cx.TypeSignatureDecoder, gc);
134+
entity = new FunctionPointerType(this, method);
135+
break;
131136
default:
132137
throw new InternalError("Unhandled handle kind " + handle.Kind);
133138
}

csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -385,19 +385,21 @@ public override IEnumerable<IExtractionProduct> Contents
385385
case Payload.Type:
386386
case Payload.Field:
387387
case Payload.ValueType:
388-
// A generic EntityHandle.
389-
var handle = MetadataTokens.EntityHandle(payloadValue);
390-
var target = Cx.CreateGeneric(Method, handle);
391-
yield return target;
392-
if (target != null)
393388
{
394-
yield return Tuples.cil_access(this, target);
389+
// A generic EntityHandle.
390+
var handle = MetadataTokens.EntityHandle(payloadValue);
391+
var target = Cx.CreateGeneric(Method, handle);
392+
yield return target;
393+
if (target != null)
394+
{
395+
yield return Tuples.cil_access(this, target);
396+
}
397+
else
398+
{
399+
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
400+
}
401+
break;
395402
}
396-
else
397-
{
398-
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
399-
}
400-
break;
401403
case Payload.Arg8:
402404
case Payload.Arg16:
403405
if (Method.Parameters is object)
@@ -417,10 +419,33 @@ public override IEnumerable<IExtractionProduct> Contents
417419
case Payload.Target32:
418420
case Payload.Switch:
419421
case Payload.Ignore8:
420-
case Payload.CallSiteDesc:
421422
// These are not handled here.
422423
// Some of these are handled by JumpContents().
423424
break;
425+
case Payload.CallSiteDesc:
426+
{
427+
var handle = MetadataTokens.EntityHandle(payloadValue);
428+
IExtractedEntity? target = null;
429+
try
430+
{
431+
target = Cx.CreateGeneric(Method, handle);
432+
}
433+
catch (Exception exc)
434+
{
435+
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}");
436+
}
437+
438+
if (target != null)
439+
{
440+
yield return target;
441+
yield return Tuples.cil_access(this, target);
442+
}
443+
else
444+
{
445+
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
446+
}
447+
break;
448+
}
424449
default:
425450
throw new InternalError($"Unhandled payload type {PayloadType}");
426451
}

csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,13 @@ class MissingValue extends InstructionViolation {
7979
* A call that does not have exactly one `getTarget()`.
8080
*/
8181
class MissingCallTarget extends InstructionViolation {
82-
MissingCallTarget() { exists(Call c | c = instruction | count(c.getTarget()) != 1) }
82+
MissingCallTarget() {
83+
exists(Call c | c = instruction |
84+
count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli
85+
or
86+
count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli
87+
)
88+
}
8389

8490
override string getMessage() { result = "Call has invalid target" }
8591
}

csharp/ql/src/semmle/code/cil/Instructions.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,22 @@ module Opcodes {
482482
override string getOpcodeName() { result = "call" }
483483
}
484484

485+
/** A `calli` instruction. */
486+
class Calli extends Call, @cil_calli {
487+
override string getOpcodeName() { result = "calli" }
488+
489+
override Callable getTarget() { none() }
490+
491+
/** Gets the function pointer type targetted by this instruction. */
492+
FunctionPointerType getTargetType() { cil_access(this, result) }
493+
494+
// The number of items popped/pushed from the stack depends on the target of
495+
// the call. Also, we need to pop the function pointer itself too.
496+
override int getPopCount() { result = getTargetType().getCallPopCount() + 1 }
497+
498+
override int getPushCount() { result = getTargetType().getCallPushCount() }
499+
}
500+
485501
/** A `callvirt` instruction. */
486502
class Callvirt extends Call, @cil_callvirt {
487503
override string getOpcodeName() { result = "callvirt" }

csharp/ql/src/semmle/code/cil/Types.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,15 @@ class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable,
310310
int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) }
311311

312312
override string toString() { result = Type.super.toString() }
313+
314+
/** Holds if the return type is `void`. */
315+
predicate returnsVoid() { getReturnType() instanceof VoidType }
316+
317+
/** Gets the number of stack items pushed in a call to this method. */
318+
int getCallPushCount() { if returnsVoid() then result = 0 else result = 1 }
319+
320+
/** Gets the number of stack items popped in a call to this method. */
321+
int getCallPopCount() { result = count(getRawParameter(_)) }
322+
323+
override string getLabel() { result = getName() }
313324
}

csharp/ql/src/semmle/code/csharp/Type.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,8 @@ class FunctionPointerType extends Type, Parameterizable, @function_pointer_type
902902
AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) }
903903

904904
override string getAPrimaryQlClass() { result = "FunctionPointerType" }
905+
906+
override string getLabel() { result = getName() }
905907
}
906908

907909
/**
Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1 @@
1-
| DispatchTailCalls | No label |
2-
| EnumCalendarInfo | No label |
31
| Finalize | Overridden method from System.Object is not in a base type |
4-
| Unknown instruction in DispatchTailCalls | Call has invalid target |
5-
| Unknown instruction in DispatchTailCalls | Cfg node has 0 pop counts |
6-
| Unknown instruction in DispatchTailCalls | Cfg node has 0 push counts |
7-
| Unknown instruction in DispatchTailCalls | Inconsistent stack size |
8-
| Unknown instruction in DispatchTailCalls | Opcode 41 is missing a QL class |
9-
| bne.un.s | Inconsistent stack size |
10-
| conv.u | Inconsistent stack size |
11-
| delegate* managed<IntPtr,IntPtr,IntPtr*,Void> | No label |
12-
| delegate* unmanaged<Char*,IntPtr,Void> | No label |
13-
| ldarg.1 | Inconsistent stack size |
14-
| ldc.i4.0 | Inconsistent stack size |
15-
| ldfld | Inconsistent stack size |
16-
| ldloc.3 | Inconsistent stack size |
17-
| leave.s | Inconsistent stack size |
18-
| ret | Inconsistent stack size |
19-
| starg.s | Inconsistent stack size |

0 commit comments

Comments
 (0)