Skip to content

Commit 2d84881

Browse files
committed
Expand IL test coverage and improve extractor file handling
Added multiple new methods to SimpleClass.cs to test a wide range of IL instructions, including floating point operations, array manipulation, pointer operations, field access, conversions, boxing/unboxing, exception handling, type checks, bitwise and comparison operations, and switch statements. Updated TestAssembly.csproj to allow unsafe blocks for pointer tests. Refactored ILExtractor.cs to dispose assemblies before copying files and improved archive path handling for source archiving.
1 parent 872d9a5 commit 2d84881

3 files changed

Lines changed: 173 additions & 20 deletions

File tree

binary/extractor/cil/Semmle.Extraction.CSharp.IL/ILExtractor.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,38 @@ public ILExtractor(TrapWriter trapWriter) {
1919
public void Extract(string dllPath) {
2020
Console.WriteLine($"Extracting {dllPath}...");
2121

22-
var assembly = AssemblyDefinition.ReadAssembly(dllPath);
23-
24-
// Write file info
25-
var fileId = trap.GetId();
26-
trap.WriteTuple("files", fileId, dllPath);
27-
28-
// Write assembly info
29-
var assemblyId = trap.GetId();
30-
trap.WriteTuple("assemblies", assemblyId, fileId, assembly.Name.Name,
31-
assembly.Name.Version.ToString());
32-
33-
foreach (var module in assembly.Modules) {
34-
foreach (var type in module.Types) {
35-
// Skip compiler-generated types for now
36-
if (type.Name.Contains("<") || type.Name.StartsWith("<"))
37-
continue;
38-
39-
ExtractType(type);
22+
// Read and process the assembly in a scoped block so it's disposed before file copy
23+
using (var assembly = AssemblyDefinition.ReadAssembly(dllPath)) {
24+
// Write file info
25+
var fileId = trap.GetId();
26+
trap.WriteTuple("files", fileId, dllPath);
27+
28+
// Write assembly info
29+
var assemblyId = trap.GetId();
30+
trap.WriteTuple("assemblies", assemblyId, fileId, assembly.Name.Name,
31+
assembly.Name.Version.ToString());
32+
33+
foreach (var module in assembly.Modules) {
34+
foreach (var type in module.Types) {
35+
// Skip compiler-generated types for now
36+
if (type.Name.Contains("<") || type.Name.StartsWith("<"))
37+
continue;
38+
39+
ExtractType(type);
40+
}
4041
}
4142
}
4243

44+
// Copy to source archive (after assembly is closed)
4345
var cilSourceArchiveDir = Environment.GetEnvironmentVariable(
4446
"CODEQL_EXTRACTOR_CIL_SOURCE_ARCHIVE_DIR");
4547
if (string.IsNullOrEmpty(cilSourceArchiveDir)) {
4648
throw new InvalidOperationException(
4749
"Environment variable CODEQL_EXTRACTOR_CIL_SOURCE_ARCHIVE_DIR is not set.");
4850
}
49-
var dllArchivePath =
50-
Path.Combine(cilSourceArchiveDir, dllPath.Replace(":", "_"));
51+
// Convert absolute path to relative for archive: strip leading / or drive letter
52+
var relativeDllPath = dllPath.TrimStart('/').Replace(":", "_");
53+
var dllArchivePath = Path.Combine(cilSourceArchiveDir, relativeDllPath);
5154
// Ensure directory exists
5255
var archiveDir = Path.GetDirectoryName(dllArchivePath);
5356
if (!Directory.Exists(archiveDir)) {

binary/test-inputs/TestAssembly/SimpleClass.cs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,154 @@ public void LoopExample()
3232
Console.WriteLine(i);
3333
}
3434
}
35+
36+
// Test float and double constants (ldc.r4, ldc.r8)
37+
public float GetPi()
38+
{
39+
return 3.14159f;
40+
}
41+
42+
public double GetE()
43+
{
44+
return 2.71828;
45+
}
46+
47+
public double FloatArithmetic(float a, double b)
48+
{
49+
float localFloat = 1.5f;
50+
double localDouble = 2.5;
51+
return (a + localFloat) * (b + localDouble);
52+
}
53+
54+
// Test more local variable operations
55+
public int LocalVariableTest()
56+
{
57+
int a = 1;
58+
int b = 2;
59+
int c = 3;
60+
int d = 4;
61+
int e = 5; // Forces use of ldloc.s/stloc.s for indices >= 4
62+
return a + b + c + d + e;
63+
}
64+
65+
// Test array operations (ldelem, stelem)
66+
public int ArrayTest()
67+
{
68+
int[] arr = new int[5];
69+
arr[0] = 10;
70+
arr[1] = 20;
71+
arr[2] = 30;
72+
return arr[0] + arr[1] + arr[2];
73+
}
74+
75+
public float[] FloatArrayTest()
76+
{
77+
float[] arr = new float[3];
78+
arr[0] = 1.1f;
79+
arr[1] = 2.2f;
80+
arr[2] = 3.3f;
81+
return arr;
82+
}
83+
84+
// Test indirect load/store (ldind, stind)
85+
public unsafe void PointerTest()
86+
{
87+
int value = 42;
88+
int* ptr = &value;
89+
*ptr = 100;
90+
int result = *ptr;
91+
}
92+
93+
// Test field operations (ldfld, stfld, ldsfld, stsfld)
94+
private int _instanceField = 0;
95+
private static int _staticField = 0;
96+
97+
public void FieldTest()
98+
{
99+
_instanceField = 10;
100+
int x = _instanceField;
101+
_staticField = 20;
102+
int y = _staticField;
103+
}
104+
105+
// Test conversions (conv.*)
106+
public void ConversionTest()
107+
{
108+
int i = 42;
109+
long l = (long)i; // conv.i8
110+
float f = (float)i; // conv.r4
111+
double d = (double)i; // conv.r8
112+
byte b = (byte)i; // conv.u1
113+
short s = (short)i; // conv.i2
114+
}
115+
116+
// Test boxing/unboxing
117+
public void BoxingTest()
118+
{
119+
int value = 42;
120+
object boxed = value; // box
121+
int unboxed = (int)boxed; // unbox.any
122+
}
123+
124+
// Test exception handling
125+
public void ExceptionTest()
126+
{
127+
try
128+
{
129+
throw new InvalidOperationException("test");
130+
}
131+
catch (InvalidOperationException ex)
132+
{
133+
Console.WriteLine(ex.Message);
134+
}
135+
finally
136+
{
137+
Console.WriteLine("finally");
138+
}
139+
}
140+
141+
// Test type checking (isinst, castclass)
142+
public void TypeCheckTest(object obj)
143+
{
144+
if (obj is string str) // isinst
145+
{
146+
Console.WriteLine(str);
147+
}
148+
149+
var cast = (SimpleClass)obj; // castclass
150+
}
151+
152+
// Test bitwise operations
153+
public int BitwiseTest(int a, int b)
154+
{
155+
int andResult = a & b;
156+
int orResult = a | b;
157+
int xorResult = a ^ b;
158+
int notResult = ~a;
159+
int shlResult = a << 2;
160+
int shrResult = a >> 2;
161+
return andResult + orResult + xorResult + notResult + shlResult + shrResult;
162+
}
163+
164+
// Test comparison operations (ceq, clt, cgt)
165+
public bool ComparisonTest(int a, int b)
166+
{
167+
bool eq = a == b;
168+
bool lt = a < b;
169+
bool gt = a > b;
170+
return eq || lt || gt;
171+
}
172+
173+
// Test switch statement
174+
public string SwitchTest(int value)
175+
{
176+
switch (value)
177+
{
178+
case 0: return "zero";
179+
case 1: return "one";
180+
case 2: return "two";
181+
default: return "other";
182+
}
183+
}
35184
}
36185
}

binary/test-inputs/TestAssembly/TestAssembly.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<OutputType>Library</OutputType>
8+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
89
</PropertyGroup>
910

1011
</Project>

0 commit comments

Comments
 (0)