Certain call patterns from JS to .NET can cause a crash when "unwrapping" the this object for a method call, in JSValue.Unwrap() on this line:
return GCHandle.FromIntPtr(result).Target!;
The crash is due to a null or invalid handle (result) value. It seems to be more likely when calling .NET async methods from JS. And much easier to repro by forcing a .NET and/or Node.js GC.
dotnet pack from root (for some extra debugging output related to GCHandle wrap/unwrap)
cd examples/dotnet-module
dotnet build
node --expose-gc example.js
Occasionally it will run and just keep counting with no errors. But usually it crashes right away with an exception similar to this:
Unwrapping GC handle 0000000000000004
Error unwrapping 0000000000000004: System.NullReferenceException: Object reference not set to an instance of an object.
at System.Runtime.InteropServices.GCHandle.get_Target()
at Microsoft.JavaScript.NodeApi.JSValue.Unwrap(String unwrapType)
Or sometimes the GC handle value might be more random junk that causes an AV:
Unwrapping handle 00007FFAC2233D88
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication > that other memory is corrupt.
In either case the GC handle value is wrong, since the correct handle values can be seen in previous logging. For some reason napi_unwrap() is returning bad values, even when its return value is napi_ok. It is definitely being called from the JS thread, since it is the start of a callback, unwrapping the this value.
Certain call patterns from JS to .NET can cause a crash when "unwrapping" the
this
object for a method call, inJSValue.Unwrap()
on this line:The crash is due to a null or invalid handle (
result
) value. It seems to be more likely when calling .NET async methods from JS. And much easier to repro by forcing a .NET and/or Node.js GC.Repro steps:
dotnet pack
from root (for some extra debugging output related to GCHandle wrap/unwrap)cd examples/dotnet-module
dotnet build
node --expose-gc example.js
Occasionally it will run and just keep counting with no errors. But usually it crashes right away with an exception similar to this:
Or sometimes the GC handle value might be more random junk that causes an AV:
In either case the GC handle value is wrong, since the correct handle values can be seen in previous logging. For some reason
napi_unwrap()
is returning bad values, even when its return value isnapi_ok
. It is definitely being called from the JS thread, since it is the start of a callback, unwrapping thethis
value.