Skip to content

Commit 6c8479a

Browse files
authored
Merge pull request #501 from bluewingHuang/issue-499-addtest
add a fail test for Issue499
2 parents 344fa12 + 4c72cff commit 6c8479a

2 files changed

Lines changed: 183 additions & 1 deletion

File tree

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2588,8 +2588,14 @@ private static bool TryEmitIndexGet(IndexExpression indexExpr,
25882588
var indexArgs = indexExpr.Arguments;
25892589
#endif
25902590
var indexArgCount = indexArgs.GetCount();
2591+
// Strip InstanceAccess when emitting arguments: they are parameters to the indexer
2592+
// getter method, not instances. Without this, a nested IndexExpression like
2593+
// `list[i][j]` leaks the outer InstanceAccess into the inner indexer's argument
2594+
// emission, causing value-type args (e.g. int) to be loaded by address (ldloca)
2595+
// instead of by value (ldloc), producing invalid IL. See #499.
2596+
var argParent = p & ~ParentFlags.InstanceAccess;
25912597
for (var i = 0; i < indexArgCount; i++)
2592-
if (!TryEmit(indexArgs.GetArgument(i), paramExprs, il, ref closure, setup, p, -1))
2598+
if (!TryEmit(indexArgs.GetArgument(i), paramExprs, il, ref closure, setup, argParent, -1))
25932599
return false;
25942600

25952601
var indexerProp = indexExpr.Indexer;

test/FastExpressionCompiler.IssueTests/Issue499_InvalidProgramException_for_Sorting_and_comparison_function.cs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23

34
#if LIGHT_EXPRESSION
45
using FastExpressionCompiler.LightExpression.ImTools;
@@ -16,6 +17,10 @@ public void Run(TestRun t)
1617
{
1718
Quicksort_partition_with_nested_loops(t);
1819
Comparison_function_with_goto_labels(t);
20+
ArrayInList_NullableInt_ArrayAccessError(t);
21+
ArrayInList_Int_ArrayAccessError(t);
22+
ArrayInList_String_ArrayAccessError(t);
23+
ArrayInList_Struct_ArrayAccess(t);
1924
}
2025

2126
// Reproduces the sorting use-case from https://github.com/dadhi/FastExpressionCompiler/issues/499
@@ -152,4 +157,175 @@ public void Comparison_function_with_goto_labels(TestContext t)
152157
t.AreEqual(-1, ff(3, 1));
153158
t.AreEqual(1, ff(1, 3));
154159
}
160+
161+
/// <summary>
162+
/// ff raise System.InvalidProgramException: Common Language Runtime detected an invalid program.
163+
/// </summary>
164+
/// <param name="t"></param>
165+
public void ArrayInList_NullableInt_ArrayAccessError(TestContext t)
166+
{
167+
List<Expression> exps = new List<Expression>();
168+
var dataArrayList = Parameter(typeof(List<int?[]>), "dataArrayList");
169+
List<ParameterExpression> vars = new List<ParameterExpression>();
170+
var left_ListIndex = Parameter(typeof(int), "left_ListIndex");
171+
var left_ArrayIndex = Parameter(typeof(int), "left_ArrayIndex");
172+
173+
vars.AddRange(new ParameterExpression[] { left_ListIndex, left_ArrayIndex });
174+
var leftVars = new ParameterExpression[1];
175+
leftVars[0] = Parameter(typeof(int?), $"left_{0}");
176+
vars.Add(leftVars[0]);
177+
exps.Add(Assign(left_ListIndex, Constant(0)));
178+
exps.Add(Assign(left_ArrayIndex, Constant(0)));
179+
exps.Add(Assign(leftVars[0], ArrayAccess(Expression.Property(dataArrayList, "Item", left_ListIndex), left_ArrayIndex)));
180+
LabelTarget endMain = Expression.Label(typeof(int?), "endMain");
181+
exps.Add(Expression.Label(endMain, leftVars[0]));
182+
183+
BlockExpression block = Block(
184+
vars.ToArray(), exps
185+
);
186+
var expr = Lambda<Func<List<int?[]>, int?>>(block, dataArrayList);
187+
expr.PrintCSharp();
188+
189+
List<int?[]> data1 = new List<int?[]> { new int?[] { 1 } };
190+
List<int?[]> data2 = new List<int?[]> { new int?[] { 1 } };
191+
192+
var fs = expr.CompileSys();
193+
fs.PrintIL();
194+
t.AreEqual(1, fs(data1));
195+
196+
var ff = expr.CompileFast(ifFastFailedReturnNull: true);
197+
t.IsNotNull(ff);
198+
ff.PrintIL();
199+
t.AreEqual(1, ff(data2));
200+
}
201+
202+
/// <summary>
203+
/// ff raise System.InvalidProgramException: Common Language Runtime detected an invalid program.
204+
/// </summary>
205+
/// <param name="t"></param>
206+
public void ArrayInList_Int_ArrayAccessError(TestContext t)
207+
{
208+
List<Expression> exps = new List<Expression>();
209+
var dataArrayList = Parameter(typeof(List<int[]>), "dataArrayList");
210+
List<ParameterExpression> vars = new List<ParameterExpression>();
211+
var left_ListIndex = Parameter(typeof(int), "left_ListIndex");
212+
var left_ArrayIndex = Parameter(typeof(int), "left_ArrayIndex");
213+
214+
vars.AddRange(new ParameterExpression[] { left_ListIndex, left_ArrayIndex });
215+
var leftVars = new ParameterExpression[1];
216+
leftVars[0] = Parameter(typeof(int), $"left_{0}");
217+
vars.Add(leftVars[0]);
218+
exps.Add(Assign(left_ListIndex, Constant(0)));
219+
exps.Add(Assign(left_ArrayIndex, Constant(0)));
220+
exps.Add(Assign(leftVars[0], ArrayAccess(Expression.Property(dataArrayList, "Item", left_ListIndex), left_ArrayIndex)));
221+
LabelTarget endMain = Expression.Label(typeof(int), "endMain");
222+
exps.Add(Expression.Label(endMain, leftVars[0]));
223+
224+
BlockExpression block = Block(
225+
vars.ToArray(), exps
226+
);
227+
var expr = Lambda<Func<List<int[]>, int>>(block, dataArrayList);
228+
expr.PrintCSharp();
229+
230+
List<int[]> data1 = new List<int[]> { new int[] { 1 } };
231+
List<int[]> data2 = new List<int[]> { new int[] { 1 } };
232+
233+
var fs = expr.CompileSys();
234+
fs.PrintIL();
235+
t.AreEqual(1, fs(data1));
236+
237+
var ff = expr.CompileFast(ifFastFailedReturnNull: true);
238+
t.IsNotNull(ff);
239+
ff.PrintIL();
240+
t.AreEqual(1, ff(data2));
241+
}
242+
243+
244+
/// <summary>
245+
/// ff raise System.InvalidProgramException: Common Language Runtime detected an invalid program.
246+
/// </summary>
247+
/// <param name="t"></param>
248+
public void ArrayInList_String_ArrayAccessError(TestContext t)
249+
{
250+
List<Expression> exps = new List<Expression>();
251+
var dataArrayList = Parameter(typeof(List<string[]>), "dataArrayList");
252+
List<ParameterExpression> vars = new List<ParameterExpression>();
253+
var left_ListIndex = Parameter(typeof(int), "left_ListIndex");
254+
var left_ArrayIndex = Parameter(typeof(int), "left_ArrayIndex");
255+
256+
vars.AddRange(new ParameterExpression[] { left_ListIndex, left_ArrayIndex });
257+
var leftVars = new ParameterExpression[1];
258+
leftVars[0] = Parameter(typeof(string), $"left_{0}");
259+
vars.Add(leftVars[0]);
260+
exps.Add(Assign(left_ListIndex, Constant(0)));
261+
exps.Add(Assign(left_ArrayIndex, Constant(0)));
262+
exps.Add(Assign(leftVars[0], ArrayAccess(Expression.Property(dataArrayList, "Item", left_ListIndex), left_ArrayIndex)));
263+
LabelTarget endMain = Expression.Label(typeof(string), "endMain");
264+
exps.Add(Expression.Label(endMain, leftVars[0]));
265+
266+
BlockExpression block = Block(
267+
vars.ToArray(), exps
268+
);
269+
var expr = Lambda<Func<List<string[]>, string>>(block, dataArrayList);
270+
expr.PrintCSharp();
271+
272+
List<string[]> data1 = new List<string[]> { new string[] { "test1" } };
273+
List<string[]> data2 = new List<string[]> { new string[] { "test2" } };
274+
var fs = expr.CompileSys();
275+
fs.PrintIL();
276+
t.AreEqual("test1", fs(data1));
277+
278+
var ff = expr.CompileFast(ifFastFailedReturnNull: true);
279+
t.IsNotNull(ff);
280+
ff.PrintIL();
281+
t.AreEqual("test2", ff(data2));
282+
}
283+
284+
/// <summary>
285+
/// passed before fix issue 499
286+
/// </summary>
287+
/// <param name="t"></param>
288+
public void ArrayInList_Struct_ArrayAccess(TestContext t)
289+
{
290+
List<Expression> exps = new List<Expression>();
291+
var dataArrayList = Parameter(typeof(List<SomeStruct[]>), "dataArrayList");
292+
List<ParameterExpression> vars = new List<ParameterExpression>();
293+
var left_ListIndex = Parameter(typeof(int), "left_ListIndex");
294+
var left_ArrayIndex = Parameter(typeof(int), "left_ArrayIndex");
295+
296+
vars.AddRange(new ParameterExpression[] { left_ListIndex, left_ArrayIndex });
297+
var leftVars = new ParameterExpression[1];
298+
leftVars[0] = Parameter(typeof(int?), $"left_{0}");
299+
vars.Add(leftVars[0]);
300+
exps.Add(Assign(left_ListIndex, Constant(0)));
301+
exps.Add(Assign(left_ArrayIndex, Constant(0)));
302+
exps.Add(Assign(leftVars[0], Property(ArrayAccess(Property(dataArrayList, "Item", left_ListIndex), left_ArrayIndex), "Foo")));
303+
LabelTarget endMain = Expression.Label(typeof(int?), "endMain");
304+
exps.Add(Expression.Label(endMain, leftVars[0]));
305+
306+
BlockExpression block = Block(
307+
vars.ToArray(), exps
308+
);
309+
var expr = Lambda<Func<List<SomeStruct[]>, int?>>(block, dataArrayList);
310+
expr.PrintCSharp();
311+
312+
List<SomeStruct[]> data1 = new List<SomeStruct[]> { new SomeStruct[] { new SomeStruct { Foo = 1 } } };
313+
List<SomeStruct[]> data2 = new List<SomeStruct[]> { new SomeStruct[] { new SomeStruct { Foo = 1 } } };
314+
315+
var fs = expr.CompileSys();
316+
fs.PrintIL();
317+
var resultFs = fs(data1);
318+
t.AreEqual(1, resultFs);
319+
320+
var ff = expr.CompileFast(ifFastFailedReturnNull: true);
321+
t.IsNotNull(ff);
322+
ff.PrintIL();
323+
var resultFf = ff(data2);
324+
t.AreEqual(1, resultFf);
325+
}
326+
327+
public struct SomeStruct
328+
{
329+
public int? Foo { get; set; }
330+
}
155331
}

0 commit comments

Comments
 (0)