Skip to content

Commit 3ece8c3

Browse files
authored
Merge pull request #4835 from tamasvajk/feature/cil-fnptr
C#: Extract function pointer types from CIL
2 parents c1726ed + eac69c1 commit 3ece8c3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+9352
-3106
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Function pointer types (`FunctionPointerType`) are extracted from IL. Also, `pinned` and `by-reference` (`cil_type_annotation`) type extraction is fixed.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
5+
namespace Semmle.Extraction.CIL.Entities
6+
{
7+
/// <summary>
8+
/// Types that are passed by reference are not written directly to trap files. Instead, the annotation is stored on
9+
/// the entity.
10+
/// </summary>
11+
internal sealed class ByRefType : Type
12+
{
13+
public ByRefType(Context cx, Type elementType) : base(cx)
14+
{
15+
ElementType = elementType;
16+
}
17+
18+
public override CilTypeKind Kind => throw new NotImplementedException();
19+
20+
public override Namespace? ContainingNamespace => throw new NotImplementedException();
21+
22+
public override Type? ContainingType => throw new NotImplementedException();
23+
24+
public override int ThisTypeParameterCount => throw new NotImplementedException();
25+
26+
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
27+
28+
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
29+
30+
public override string Name => $"{ElementType.Name}&";
31+
32+
public Type ElementType { get; }
33+
34+
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
35+
36+
public override void WriteId(TextWriter trapFile, bool inContext)
37+
{
38+
ElementType.WriteId(trapFile, inContext);
39+
trapFile.Write('&');
40+
}
41+
}
42+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public enum CilTypeKind
88
ValueOrRefType,
99
TypeParameter,
1010
Array,
11-
Pointer
11+
Pointer,
12+
FunctionPointer
1213
}
1314
}

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,19 @@ public override IEnumerable<IExtractionProduct> Contents
121121

122122
for (var l = 0; l < this.locals.Length; ++l)
123123
{
124-
this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, localVariableTypes[l]));
125-
yield return this.locals[l];
124+
var t = localVariableTypes[l];
125+
if (t is ByRefType brt)
126+
{
127+
t = brt.ElementType;
128+
this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, t));
129+
yield return this.locals[l];
130+
yield return Tuples.cil_type_annotation(this.locals[l], TypeAnnotation.Ref);
131+
}
132+
else
133+
{
134+
this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, t));
135+
yield return this.locals[l];
136+
}
126137
}
127138
}
128139

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Reflection.Metadata;
5+
6+
namespace Semmle.Extraction.CIL.Entities
7+
{
8+
internal sealed class FunctionPointerType : Type, IParameterizable, ICustomModifierReceiver
9+
{
10+
private readonly MethodSignature<Type> signature;
11+
12+
public FunctionPointerType(Context cx, MethodSignature<Type> signature) : base(cx)
13+
{
14+
this.signature = signature;
15+
}
16+
17+
public override CilTypeKind Kind => CilTypeKind.FunctionPointer;
18+
19+
public override string Name
20+
{
21+
get
22+
{
23+
using var id = new StringWriter();
24+
WriteName(
25+
id.Write,
26+
t => id.Write(t.Name),
27+
signature
28+
);
29+
return id.ToString();
30+
}
31+
}
32+
33+
public override Namespace? ContainingNamespace => Cx.GlobalNamespace;
34+
35+
public override Type? ContainingType => null;
36+
37+
public override int ThisTypeParameterCount => throw new System.NotImplementedException();
38+
39+
public override IEnumerable<Type> TypeParameters => throw new System.NotImplementedException();
40+
41+
public override Type Construct(IEnumerable<Type> typeArguments) => throw new System.NotImplementedException();
42+
43+
public override void WriteAssemblyPrefix(TextWriter trapFile) { }
44+
45+
public override void WriteId(TextWriter trapFile, bool inContext)
46+
{
47+
WriteName(
48+
trapFile.Write,
49+
t => t.WriteId(trapFile, inContext),
50+
signature
51+
);
52+
}
53+
54+
internal static void WriteName<TType>(Action<string> write, Action<TType> writeType, MethodSignature<TType> signature)
55+
{
56+
write("delegate* ");
57+
write(GetCallingConvention(signature.Header.CallingConvention));
58+
write("<");
59+
foreach (var pt in signature.ParameterTypes)
60+
{
61+
writeType(pt);
62+
write(",");
63+
}
64+
writeType(signature.ReturnType);
65+
write(">");
66+
}
67+
68+
internal static string GetCallingConvention(SignatureCallingConvention callingConvention)
69+
{
70+
if (callingConvention == SignatureCallingConvention.Default)
71+
{
72+
return "managed";
73+
}
74+
75+
if (callingConvention == SignatureCallingConvention.Unmanaged)
76+
{
77+
return "unmanaged";
78+
}
79+
80+
return $"unmanaged[{callingConvention}]";
81+
}
82+
83+
public override IEnumerable<IExtractionProduct> Contents
84+
{
85+
get
86+
{
87+
foreach (var c in base.Contents)
88+
{
89+
yield return c;
90+
}
91+
92+
var retType = signature.ReturnType;
93+
if (retType is ModifiedType mt)
94+
{
95+
retType = mt.Unmodified;
96+
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
97+
}
98+
if (retType is ByRefType byRefType)
99+
{
100+
retType = byRefType.ElementType;
101+
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
102+
}
103+
yield return Tuples.cil_function_pointer_return_type(this, retType);
104+
105+
yield return Tuples.cil_function_pointer_calling_conventions(this, signature.Header.CallingConvention);
106+
107+
foreach (var p in Method.GetParameterExtractionProducts(signature.ParameterTypes, this, this, Cx, 0))
108+
{
109+
yield return p;
110+
}
111+
}
112+
}
113+
}
114+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Semmle.Extraction.CIL.Entities
2+
{
3+
internal interface IParameterizable : IEntity
4+
{
5+
6+
}
7+
}

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

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL.Entities
99
/// <summary>
1010
/// A method entity.
1111
/// </summary>
12-
internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver
12+
internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver, IParameterizable
1313
{
1414
protected MethodTypeParameter[]? genericParams;
1515
protected GenericContext gc;
@@ -86,15 +86,34 @@ protected IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumer
8686
yield return Cx.Populate(new Parameter(Cx, this, i++, DeclaringType));
8787
}
8888

89+
foreach (var p in GetParameterExtractionProducts(parameterTypes, this, this, Cx, i))
90+
{
91+
yield return p;
92+
}
93+
}
94+
95+
internal static IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumerable<Type> parameterTypes, IParameterizable parameterizable, ICustomModifierReceiver receiver, Context cx, int firstChildIndex)
96+
{
97+
var i = firstChildIndex;
8998
foreach (var p in parameterTypes)
9099
{
91100
var t = p;
92101
if (t is ModifiedType mt)
93102
{
94103
t = mt.Unmodified;
95-
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
104+
yield return Tuples.cil_custom_modifiers(receiver, mt.Modifier, mt.IsRequired);
105+
}
106+
if (t is ByRefType brt)
107+
{
108+
t = brt.ElementType;
109+
var parameter = cx.Populate(new Parameter(cx, parameterizable, i++, t));
110+
yield return parameter;
111+
yield return Tuples.cil_type_annotation(parameter, TypeAnnotation.Ref);
112+
}
113+
else
114+
{
115+
yield return cx.Populate(new Parameter(cx, parameterizable, i++, t));
96116
}
97-
yield return Cx.Populate(new Parameter(Cx, this, i++, t));
98117
}
99118
}
100119

@@ -106,6 +125,11 @@ protected IEnumerable<IExtractionProduct> GetMethodExtractionProducts(string nam
106125
t = mt.Unmodified;
107126
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
108127
}
128+
if (t is ByRefType brt)
129+
{
130+
t = brt.ElementType;
131+
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
132+
}
109133
yield return Tuples.cil_method(this, name, declaringType, t);
110134
}
111135
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ public ModifiedType(Context cx, Type unmodified, Type modifier, bool isRequired)
3737

3838
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
3939

40-
public override void WriteId(TextWriter trapFile, bool inContext) => throw new NotImplementedException();
40+
public override void WriteId(TextWriter trapFile, bool inContext)
41+
{
42+
Unmodified.WriteId(trapFile, inContext);
43+
trapFile.Write(IsRequired ? " modreq" : " modopt");
44+
trapFile.Write("(");
45+
Modifier.WriteId(trapFile, inContext);
46+
trapFile.Write(")");
47+
}
4148
}
4249
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ namespace Semmle.Extraction.CIL.Entities
88
/// </summary>
99
internal sealed class Parameter : LabelledEntity
1010
{
11-
private readonly Method method;
11+
private readonly IParameterizable method;
1212
private readonly int index;
1313
private readonly Type type;
1414

15-
public Parameter(Context cx, Method m, int i, Type t) : base(cx)
15+
public Parameter(Context cx, IParameterizable m, int i, Type t) : base(cx)
1616
{
1717
method = m;
1818
index = i;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public override IEnumerable<IExtractionProduct> Contents
6262
t = mt.Unmodified;
6363
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
6464
}
65+
if (t is ByRefType brt)
66+
{
67+
t = brt.ElementType;
68+
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
69+
}
6570
yield return Tuples.cil_property(this, type, name, t);
6671

6772
var accessors = pd.GetAccessors();

0 commit comments

Comments
 (0)