Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expression trees - invoke lambda during loop leads to variable leaking

I have found little issue with expression trees and would like to know whether such is a bug or a feature. I have this code. The first function assigns one to a variable and returns it.

static class Functions 
{
    static public Expression<Func<int>> GetOne()
    {
        //Returns something like this () => {int x; return x +1;}
        var variable = Expression.Variable(typeof(int));
        var f = Expression.Lambda<Func<int>>(
                            Expression.Block(
                            new[] { variable },
                            Expression.Assign(variable, Expression.Add(variable, Expression.Constant(1)))
        ));
        return f;
    }
    
    static public Expression<Func<int>> ApplyTenTimes()
    {
        var i = Expression.Variable(typeof(int));
        var breakLabel = Expression.Label();
        var f = GetOne();
        var loop = Expression.Lambda<Func<int>>(
        Expression.Block(
            new[] { i },
            Expression.Block(
            new Expression[] {
            Expression.Loop(Expression.Block(
                        Expression.IfThen(Expression.Equal(i, Expression.Constant(10)),          Expression.Break(breakLabel)),
                Expression.PostIncrementAssign(i),
                Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),   Expression.Call( Expression.Invoke(f),typeof(int).GetMethod("ToString", new Type[0]))
                    ))),
            Expression.Label(breakLabel),
            Expression.Invoke(f)
            })));
    
        return loop;
    }
}
f = Functions.GetOne().Compile();
IEnumerable<int> a = Enumerable.Range(0, 9).Select(_ => f()).ToList();
//Prints 1
Console.WriteLine(f());

f = Functions.ApplyTenTimes().Compile();
//Prints 1, ..., 10, 1
Console.WriteLine(f());

I expected the f always prints 1 as 0 is a default value for int.

like image 879
Vojtech G Avatar asked Apr 09 '26 17:04

Vojtech G


1 Answers

If you try to get an interpreted delegate when calling Compile:

var f = Functions.ApplyTenTimes().Compile(preferInterpretation: true);
Console.WriteLine(f());

Then it behaves as you'd expect - "1" is printed eleven times.

Based on this fact, this is highly likely to be a bug in the expression compiler when compiling a loop expression, since the delegate should have the same behaviour regardless of whether it is interpreted or compiled.

like image 158
Sweeper Avatar answered Apr 12 '26 07:04

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!