Possible fix for lua crash #5269
Check if this instance has been disposed and don't call 'tick' if it has. Also remove the finalizer that was broken and wrong anyway. 'runtime' would never become null because it's readonly and managed resources are freed automatically or may have already been freed by then.
This commit is contained in:
@@ -81,11 +81,12 @@ namespace OpenRA.Scripting
|
|||||||
public ScriptGlobalAttribute(string name) { Name = name; }
|
public ScriptGlobalAttribute(string name) { Name = name; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ScriptContext
|
public class ScriptContext : IDisposable
|
||||||
{
|
{
|
||||||
public World World { get; private set; }
|
public World World { get; private set; }
|
||||||
public WorldRenderer WorldRenderer { get; private set; }
|
public WorldRenderer WorldRenderer { get; private set; }
|
||||||
|
|
||||||
|
bool disposed;
|
||||||
readonly MemoryConstrainedLuaRuntime runtime;
|
readonly MemoryConstrainedLuaRuntime runtime;
|
||||||
readonly LuaFunction tick;
|
readonly LuaFunction tick;
|
||||||
|
|
||||||
@@ -188,26 +189,34 @@ namespace OpenRA.Scripting
|
|||||||
|
|
||||||
public void Tick(Actor self)
|
public void Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (error)
|
if (error || disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (new PerfSample("tick_lua"))
|
using (new PerfSample("tick_lua"))
|
||||||
tick.Call().Dispose();
|
tick.Call().Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
protected void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (runtime == null)
|
if (disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
if (disposing)
|
||||||
runtime.Dispose();
|
runtime.Dispose();
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScriptContext()
|
~ScriptContext()
|
||||||
{
|
{
|
||||||
if (runtime != null)
|
// Dispose unmanaged resources only
|
||||||
Game.RunAfterTick(Dispose);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type[] ExtractRequiredTypes(Type t)
|
static Type[] ExtractRequiredTypes(Type t)
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA.Activities
|
namespace OpenRA.Mods.RA.Activities
|
||||||
{
|
{
|
||||||
public class CallLuaFunc : Activity
|
public class CallLuaFunc : Activity, IDisposable
|
||||||
{
|
{
|
||||||
LuaFunction function;
|
LuaFunction function;
|
||||||
|
|
||||||
public CallLuaFunc(LuaFunction func)
|
public CallLuaFunc(LuaFunction func)
|
||||||
{
|
{
|
||||||
function = func.CopyReference() as LuaFunction;
|
function = (LuaFunction)func.CopyReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
@@ -38,20 +39,28 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
base.Cancel(self);
|
base.Cancel(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
protected void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (function == null)
|
if (function == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
if (disposing)
|
||||||
|
{
|
||||||
function.Dispose();
|
function.Dispose();
|
||||||
function = null;
|
function = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
~CallLuaFunc()
|
~CallLuaFunc()
|
||||||
{
|
{
|
||||||
if (function != null)
|
// Dispose unmanaged resources only
|
||||||
Game.RunAfterTick(Dispose);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
|
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
|
||||||
public class ScriptTriggersInfo : TraitInfo<ScriptTriggers> { }
|
public class ScriptTriggersInfo : TraitInfo<ScriptTriggers> { }
|
||||||
|
|
||||||
public class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction
|
public class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, IDisposable
|
||||||
{
|
{
|
||||||
public event Action<Actor> OnKilledInternal = _ => {};
|
public event Action<Actor> OnKilledInternal = _ => {};
|
||||||
|
|
||||||
@@ -101,21 +101,36 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool disposed;
|
bool disposed;
|
||||||
public void Dispose()
|
|
||||||
|
protected void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
{
|
{
|
||||||
disposed = true;
|
|
||||||
var toDispose = new [] { onIdle, onDamaged, onKilled, onProduction };
|
var toDispose = new [] { onIdle, onDamaged, onKilled, onProduction };
|
||||||
|
|
||||||
foreach (var f in toDispose.SelectMany(f => f))
|
foreach (var f in toDispose.SelectMany(f => f))
|
||||||
f.First.Dispose();
|
f.First.Dispose();
|
||||||
|
|
||||||
|
foreach (var l in toDispose)
|
||||||
|
l.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScriptTriggers()
|
~ScriptTriggers()
|
||||||
{
|
{
|
||||||
if (!disposed)
|
// Dispose unmanaged resources only
|
||||||
Game.RunAfterTick(Dispose);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user