Skip to content

Commit 477b65d

Browse files
committed
Fix: Memory leak and deadlock
1 parent 130ba84 commit 477b65d

File tree

5 files changed

+129
-128
lines changed

5 files changed

+129
-128
lines changed

NeoLua.NuGet/common.targets

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<AssemblyVersion>5.3.0.0</AssemblyVersion>
1515
<FileVersion>1.3.9.0</FileVersion>
1616

17-
<VersionAdd>beta.2</VersionAdd>
17+
<VersionAdd>beta.4</VersionAdd>
1818
<SimpleVersionPattern>^(\d+)\.(\d+)\.(\d+)</SimpleVersionPattern>
1919
<SimpleVersion>$([System.Text.RegularExpressions.Regex]::Match($(FileVersion), $(SimpleVersionPattern)))</SimpleVersion>
2020

NeoLua/LuaEmit.cs

+58-59
Original file line numberDiff line numberDiff line change
@@ -1690,8 +1690,7 @@ public static LuaTryGetMemberReturn TryGetMember(Expression target, Type targetT
16901690
var luaTargetType = LuaType.GetType(targetType);
16911691
var enumerateType = GetMethodEnumeratorType(target, targetType);
16921692

1693-
var memberEnum = luaTargetType.EnumerateMembers<MemberInfo>(enumerateType, memberName, ignoreCase).GetEnumerator();
1694-
try
1693+
using (var memberEnum = luaTargetType.EnumerateMembers<MemberInfo>(enumerateType, memberName, ignoreCase).GetEnumerator())
16951694
{
16961695
if (!memberEnum.MoveNext()) // no member found
16971696
{
@@ -1764,10 +1763,6 @@ public static LuaTryGetMemberReturn TryGetMember(Expression target, Type targetT
17641763
}
17651764
}
17661765
}
1767-
finally
1768-
{
1769-
(memberEnum as IDisposable)?.Dispose();
1770-
}
17711766
} // func GetMember
17721767

17731768
private static LuaMethodEnumerate GetMethodEnumeratorType<TARG>(TARG target, Func<TARG, Expression> getExpr, Func<TARG, Type> getType)
@@ -1793,34 +1788,35 @@ private static LuaMethodEnumerate GetMethodEnumeratorType(Expression target, Typ
17931788
public static LuaTrySetMemberReturn TrySetMember(Expression target, Type targetType, string memberName, bool ignoreCase, Func<Type, Expression> set, out Expression result)
17941789
{
17951790
var luaType = LuaType.GetType(targetType);
1796-
var memberEnum = luaType.EnumerateMembers<MemberInfo>(GetMethodEnumeratorType(target, targetType), memberName, ignoreCase).GetEnumerator();
1797-
1798-
if (!memberEnum.MoveNext())
1791+
using (var memberEnum = luaType.EnumerateMembers<MemberInfo>(GetMethodEnumeratorType(target, targetType), memberName, ignoreCase).GetEnumerator())
17991792
{
1800-
result = null;
1801-
return LuaTrySetMemberReturn.None;
1802-
}
1793+
if (!memberEnum.MoveNext())
1794+
{
1795+
result = null;
1796+
return LuaTrySetMemberReturn.None;
1797+
}
18031798

1804-
var memberInfo = memberEnum.Current;
1805-
if (memberInfo is PropertyInfo propertyInfo)
1806-
{
1807-
if (!propertyInfo.CanWrite)
1799+
var memberInfo = memberEnum.Current;
1800+
if (memberInfo is PropertyInfo propertyInfo)
1801+
{
1802+
if (!propertyInfo.CanWrite)
1803+
{
1804+
result = null;
1805+
return LuaTrySetMemberReturn.NotWritable;
1806+
}
1807+
result = Expression.Assign(Expression.Property(target != null ? Lua.EnsureType(target, targetType) : null, propertyInfo), set(propertyInfo.PropertyType));
1808+
return LuaTrySetMemberReturn.ValidExpression;
1809+
}
1810+
else if (memberInfo is FieldInfo fieldInfo)
1811+
{
1812+
result = Expression.Assign(Expression.Field(target != null ? Lua.EnsureType(target, targetType) : null, fieldInfo), set(fieldInfo.FieldType));
1813+
return LuaTrySetMemberReturn.ValidExpression;
1814+
}
1815+
else
18081816
{
18091817
result = null;
18101818
return LuaTrySetMemberReturn.NotWritable;
18111819
}
1812-
result = Expression.Assign(Expression.Property(target != null ? Lua.EnsureType(target, targetType) : null, propertyInfo), set(propertyInfo.PropertyType));
1813-
return LuaTrySetMemberReturn.ValidExpression;
1814-
}
1815-
else if (memberInfo is FieldInfo fieldInfo)
1816-
{
1817-
result = Expression.Assign(Expression.Field(target != null ? Lua.EnsureType(target, targetType) : null, fieldInfo), set(fieldInfo.FieldType));
1818-
return LuaTrySetMemberReturn.ValidExpression;
1819-
}
1820-
else
1821-
{
1822-
result = null;
1823-
return LuaTrySetMemberReturn.NotWritable;
18241820
}
18251821
} // func TrySetMember
18261822

@@ -2561,42 +2557,43 @@ public static TMEMBERTYPE FindMember<TMEMBERTYPE, TARG>(IEnumerable<TMEMBERTYPE>
25612557
var memberMatchBind = new MemberMatchInfo<TMEMBERTYPE>(unboundedArguments, arguments.Length);
25622558

25632559
// get argument list
2564-
var memberEnum = members.GetEnumerator();
2565-
2566-
// reset the result with the first one
2567-
if (memberEnum.MoveNext())
2568-
memberMatch.Reset(memberEnum.Current, isMemberCall, memberMatchBind);
2569-
else
2570-
return null;
2571-
2572-
// text the rest if there is better one
2573-
if (memberEnum.MoveNext() && !memberMatchBind.IsPerfect)
2560+
using (var memberEnum = members.GetEnumerator())
25742561
{
2575-
var memberMatchCurrent = new MemberMatchInfo<TMEMBERTYPE>(unboundedArguments, arguments.Length);
2562+
// reset the result with the first one
2563+
if (memberEnum.MoveNext())
2564+
memberMatch.Reset(memberEnum.Current, isMemberCall, memberMatchBind);
2565+
else
2566+
return null;
25762567

2577-
// test
2578-
memberMatch.Reset(memberEnum.Current, isMemberCall, memberMatchCurrent);
2579-
if (memberMatchCurrent.IsBetter(memberMatchBind))
2568+
// text the rest if there is better one
2569+
if (memberEnum.MoveNext() && !memberMatchBind.IsPerfect)
25802570
{
2581-
memberMatchBind = memberMatchCurrent;
2582-
memberMatchCurrent = new MemberMatchInfo<TMEMBERTYPE>(unboundedArguments, arguments.Length);
2583-
}
2571+
var memberMatchCurrent = new MemberMatchInfo<TMEMBERTYPE>(unboundedArguments, arguments.Length);
25842572

2585-
while (memberEnum.MoveNext() && !memberMatchBind.IsPerfect)
2586-
{
25872573
// test
25882574
memberMatch.Reset(memberEnum.Current, isMemberCall, memberMatchCurrent);
25892575
if (memberMatchCurrent.IsBetter(memberMatchBind))
25902576
{
25912577
memberMatchBind = memberMatchCurrent;
25922578
memberMatchCurrent = new MemberMatchInfo<TMEMBERTYPE>(unboundedArguments, arguments.Length);
25932579
}
2580+
2581+
while (memberEnum.MoveNext() && !memberMatchBind.IsPerfect)
2582+
{
2583+
// test
2584+
memberMatch.Reset(memberEnum.Current, isMemberCall, memberMatchCurrent);
2585+
if (memberMatchCurrent.IsBetter(memberMatchBind))
2586+
{
2587+
memberMatchBind = memberMatchCurrent;
2588+
memberMatchCurrent = new MemberMatchInfo<TMEMBERTYPE>(unboundedArguments, arguments.Length);
2589+
}
2590+
}
25942591
}
2595-
}
25962592

2597-
Debug.WriteLine("USED: {0}", memberMatchBind.CurrentMember);
2593+
Debug.WriteLine("USED: {0}", memberMatchBind.CurrentMember);
25982594

2599-
return memberMatchBind.CurrentMember;
2595+
return memberMatchBind.CurrentMember;
2596+
}
26002597
} // func FindMember
26012598

26022599
private static MethodInfo MakeNonGenericMethod<TARG>(MethodInfo mi, TARG[] arguments, Func<TARG, Type> getType)
@@ -2834,22 +2831,24 @@ private static IEnumerable<T> FilterNeeded<T>(IEnumerable<T> list, ReflectionFla
28342831
return list;
28352832
} // func FilterNeeded
28362833

2837-
private static T GetOneResult<T>(TypeInfo ti, string sName, ReflectionFlag flags, IEnumerable<T> list, [CallerMemberName] string sCaller = null)
2834+
private static T GetOneResult<T>(TypeInfo ti, string name, ReflectionFlag flags, IEnumerable<T> list, [CallerMemberName] string caller = null)
28382835
{
28392836
if ((flags & ReflectionFlag.NoException) != 0)
28402837
return list.FirstOrDefault();
28412838
else
28422839
{
2843-
var e = list.GetEnumerator();
2844-
if (e.MoveNext()) // first element for return
2840+
using (var e = list.GetEnumerator())
28452841
{
2846-
var miFind = e.Current;
2847-
if (e.MoveNext())
2848-
throw new ArgumentException(String.Format("{0} for {1}.{2}, is not unique.", sCaller, ti.Name, sName));
2849-
return miFind;
2842+
if (e.MoveNext()) // first element for return
2843+
{
2844+
var miFind = e.Current;
2845+
if (e.MoveNext())
2846+
throw new ArgumentException(String.Format("{0} for {1}.{2}, is not unique.", caller, ti.Name, name));
2847+
return miFind;
2848+
}
2849+
else
2850+
throw new ArgumentException(String.Format("{0} failed for {1}.{2}.", caller, ti.Name, name));
28502851
}
2851-
else
2852-
throw new ArgumentException(String.Format("{0} failed for {1}.{2}.", sCaller, ti.Name, sName));
28532852
}
28542853
} // func GetOneResult
28552854

NeoLua/LuaGlobal.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ public static LuaResult LuaIPairs(LuaTable t)
453453
if (t == null)
454454
throw new ArgumentNullException("#1");
455455

456-
var e = new ArrayIndexEnumerator(t.ArrayList).GetEnumerator();
456+
var e = new ArrayIndexEnumerator(t.ArrayList).GetEnumerator(); // todo: possible memory leak if the enumeration does not reach the end
457457
return new LuaResult(new Func<object, object, LuaResult>(PairsEnum<int>), e, e);
458458
} // func ipairs
459459

@@ -466,7 +466,7 @@ public static LuaResult LuaMPairs(LuaTable t)
466466
if (t == null)
467467
throw new ArgumentNullException("#1");
468468

469-
var e = t.Members.GetEnumerator();
469+
var e = t.Members.GetEnumerator(); // todo: possible memory leak if the enumeration does not reach the end
470470
return new LuaResult(new Func<object, object, LuaResult>(PairsEnum<string>), e, e);
471471
} // func LuaPairs
472472

@@ -479,7 +479,7 @@ public static LuaResult LuaPairs(LuaTable t)
479479
if (t == null)
480480
throw new ArgumentNullException("#1");
481481

482-
var e = ((System.Collections.IEnumerable)t).GetEnumerator();
482+
var e = ((System.Collections.IEnumerable)t).GetEnumerator(); // todo: possible memory leak if the enumeration does not reach the end
483483
return new LuaResult(new Func<object, object, LuaResult>(PairsEnum<object>), e, e);
484484
} // func LuaPairs
485485

NeoLua/LuaLibraries.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ public static LuaResult gmatch(this string s, string pattern)
378378
pattern = TranslateRegularExpression(pattern).Item1;
379379

380380
// Find Matches
381-
var e = Regex.Matches(s, pattern).GetEnumerator();
381+
var e = Regex.Matches(s, pattern).GetEnumerator(); // todo: possible memory leak if the enumeration does not reach the end
382382
return new LuaResult(new Func<object, object, LuaResult>(MatchEnum), e, e);
383383
} // func gmatch
384384

NeoLua/Parser.cs

+66-64
Original file line numberDiff line numberDiff line change
@@ -908,88 +908,90 @@ private static void ParseExpressionStatement(Scope scope, ILuaLexer code, bool i
908908
code.Next();
909909

910910
// parse all expressions
911-
var expr = ParseExpressionList(scope, code).GetEnumerator();
912-
expr.MoveNext();
913-
914-
if (prefixes.Count == 1) // one expression, one variable?
915-
{
916-
scope.AddExpression(
917-
prefixes[0].GenerateSet(scope, expr.Current != null ? expr.Current : Expression.Constant(null, typeof(object)))
918-
);
919-
}
920-
else if (expr.Current == null) // No expression, assign null
921-
{
922-
for (var i = 0; i < prefixes.Count; i++)
923-
scope.AddExpression(prefixes[i].GenerateSet(scope, Expression.Constant(null, typeof(object))));
924-
}
925-
else // assign on an unknown number of expressions
911+
using (var expr = ParseExpressionList(scope, code).GetEnumerator())
926912
{
927-
#region -- unknown number --
928-
var assignTempVars = new List<ParameterExpression>();
929-
var assignExprs = new List<Expression>();
930-
int expressionVarOffset;
913+
expr.MoveNext();
931914

932-
// Safe the prefixes in variables
933-
for (var k = 0; k < prefixes.Count; k++)
915+
if (prefixes.Count == 1) // one expression, one variable?
934916
{
935-
var p = prefixes[k];
936-
if (p.Member != null || prefixes[k].Indices != null)
937-
{
938-
p.Instance = ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, p.Instance);
917+
scope.AddExpression(
918+
prefixes[0].GenerateSet(scope, expr.Current ?? Expression.Constant(null, typeof(object)))
919+
);
920+
}
921+
else if (expr.Current == null) // No expression, assign null
922+
{
923+
for (var i = 0; i < prefixes.Count; i++)
924+
scope.AddExpression(prefixes[i].GenerateSet(scope, Expression.Constant(null, typeof(object))));
925+
}
926+
else // assign on an unknown number of expressions
927+
{
928+
#region -- unknown number --
929+
var assignTempVars = new List<ParameterExpression>();
930+
var assignExprs = new List<Expression>();
931+
int expressionVarOffset;
939932

940-
if (p.Indices != null)
933+
// Safe the prefixes in variables
934+
for (var k = 0; k < prefixes.Count; k++)
935+
{
936+
var p = prefixes[k];
937+
if (p.Member != null || prefixes[k].Indices != null)
941938
{
942-
for (var l = 0; l < p.Indices.Length; l++)
943-
p.Indices[l] = ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, p.Indices[l]);
939+
p.Instance = ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, p.Instance);
940+
941+
if (p.Indices != null)
942+
{
943+
for (var l = 0; l < p.Indices.Length; l++)
944+
p.Indices[l] = ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, p.Indices[l]);
945+
}
944946
}
945947
}
946-
}
947948

948-
// collect the results of the expressions
949-
expressionVarOffset = assignTempVars.Count;
950-
do
951-
{
952-
ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, expr.Current);
953-
} while (expr.MoveNext());
954-
955-
// Assign the Result to the prefixes
956-
var i = 0;
957-
var j = 0;
958-
var lastVariable = (ParameterExpression)null;
959-
while (i < prefixes.Count)
960-
{
961-
if (i < assignTempVars.Count - expressionVarOffset) // are the variables
949+
// collect the results of the expressions
950+
expressionVarOffset = assignTempVars.Count;
951+
do
952+
{
953+
ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, expr.Current);
954+
} while (expr.MoveNext());
955+
956+
// Assign the Result to the prefixes
957+
var i = 0;
958+
var j = 0;
959+
var lastVariable = (ParameterExpression)null;
960+
while (i < prefixes.Count)
962961
{
963-
if (i == assignTempVars.Count - expressionVarOffset - 1 && assignTempVars[i + expressionVarOffset].Type == typeof(LuaResult)) // check if the last expression is a LuaResult
962+
if (i < assignTempVars.Count - expressionVarOffset) // are the variables
963+
{
964+
if (i == assignTempVars.Count - expressionVarOffset - 1 && assignTempVars[i + expressionVarOffset].Type == typeof(LuaResult)) // check if the last expression is a LuaResult
965+
{
966+
lastVariable = assignTempVars[i + expressionVarOffset];
967+
assignExprs.Add(prefixes[i].GenerateSet(scope, GetResultExpression(scope.Runtime, code.Current, lastVariable, j++)));
968+
}
969+
else
970+
{
971+
assignExprs.Add(prefixes[i].GenerateSet(scope, assignTempVars[i + expressionVarOffset]));
972+
}
973+
}
974+
else if (lastVariable != null) // we enroll the last expression
964975
{
965-
lastVariable = assignTempVars[i + expressionVarOffset];
966976
assignExprs.Add(prefixes[i].GenerateSet(scope, GetResultExpression(scope.Runtime, code.Current, lastVariable, j++)));
967977
}
968-
else
978+
else // no variable left
969979
{
970-
assignExprs.Add(prefixes[i].GenerateSet(scope, assignTempVars[i + expressionVarOffset]));
980+
assignExprs.Add(prefixes[i].GenerateSet(scope, Expression.Default(typeof(object))));
971981
}
982+
i++;
972983
}
973-
else if (lastVariable != null) // we enroll the last expression
974-
{
975-
assignExprs.Add(prefixes[i].GenerateSet(scope, GetResultExpression(scope.Runtime, code.Current, lastVariable, j++)));
976-
}
977-
else // no variable left
978-
{
979-
assignExprs.Add(prefixes[i].GenerateSet(scope, Expression.Default(typeof(object))));
980-
}
981-
i++;
982-
}
983984

984-
// add the block
985-
scope.AddExpression(Expression.Block(assignTempVars, assignExprs));
985+
// add the block
986+
scope.AddExpression(Expression.Block(assignTempVars, assignExprs));
986987

987-
#endregion
988-
}
988+
#endregion
989+
}
989990

990-
// Führe die restlichen Expressions aus
991-
while (expr.MoveNext())
992-
scope.AddExpression(expr.Current);
991+
// Führe die restlichen Expressions aus
992+
while (expr.MoveNext())
993+
scope.AddExpression(expr.Current);
994+
}
993995
}
994996
else if (!isLocal)
995997
{

0 commit comments

Comments
 (0)