Hello there !
We are currently working on a WebGL game that relies a lot on Cloud Code.
On WebGL, we have been systematically experiencing the same crash in the authentication steps of our game :
Uncaught TypeError: Cannot read properties of undefined (reading 'readyState')
at _WebSocketFree (test_lobah.framework.js:8088:45)
at invoke_vi (test_lobah.framework.js:18587:29)
at WebSocketFactory_HandleInstanceDestroy_mB533D21CA7D36EDF0D7D4FD279948195E8A39534 (test_lobah.wasm:0x3570a2c)
at invoke_vii (test_lobah.framework.js:18576:29)
at WebSocket_Finalize_m4CCA49F0C6CB66F0B3435546A16A14424F53E429 (test_lobah.wasm:0x357069f)
at RuntimeInvoker_TrueVoid_t4861ACF8F4594C3437BB48B6E56783494B843915(:61754/void (*)(), MethodInfo const*, void*, void**, void*) (http://localhost:61754/Build/test_lobah.wasm)
at il2cpp::vm::Runtime::InvokeWithThrow(:61754/MethodInfo const*, void*, void**) (http://localhost:61754/Build/test_lobah.wasm)
at invoke_iiii (test_lobah.framework.js:18631:36)
at il2cpp::vm::Runtime::Invoke(:61754/MethodInfo const*, void*, void**, Il2CppException**) (http://localhost:61754/Build/test_lobah.wasm)
at il2cpp::gc::GarbageCollector::RunFinalizer(:61754/void*, void*) (http://localhost:61754/Build/test_lobah.wasm)
at GC_invoke_finalizers (test_lobah.wasm:0x9a223)
at il2cpp::gc::GarbageCollector::CollectALittle(:61754/) (http://localhost:61754/Build/test_lobah.wasm)
at il2cpp_gc_collect_a_little (test_lobah.wasm:0xee475)
at scripting_gc_collect_a_little(:61754/) (http://localhost:61754/Build/test_lobah.wasm)
at MainLoop(:61754/) (http://localhost:61754/Build/test_lobah.wasm)
at _JS_CallAsLongAsNoExceptionsSeen (test_lobah.framework.js:1952:28)
at UpdateUnityFrame(:61754/) (http://localhost:61754/Build/test_lobah.wasm)
at callUserCallback (test_lobah.framework.js:5539:9)
at Object.runIter (test_lobah.framework.js:5595:11)
at Browser_mainLoop_runner (test_lobah.framework.js:6233:26)
After some investigation, we managed to isolate the issue. This happens after calling one of our cloud code modules.
We looked into the generated js code and enabled debugging for this WebSocket API, to get some logs.
What we believe happens is that Cloud Code opens a WebSocket, then closes the WebSocket when it’s done.
After a short time, the WebSocket is garbage collected and _WebSocketFree is called. This free function checks if the web socket is closed before deleting it (for safety reasons I suppose, if for whatever reason it wasn’t closed before being garbage collected or freed).
function _WebSocketFree(instanceId) {
var instance = webSocketState.instances[instanceId];
if (!instance) return 0;
console.log(`[JSLIB WebSocket] ${JSON.stringify(instance)}`);
// Close if not closed
if (instance.ws !== null && instance.ws.readyState < 2)
instance.ws.close();
// Remove reference
delete webSocketState.instances[instanceId];
return 0;
}
When we log the content of the instance, we find out that the actual websocket (instance.ws) is undefined (which makes sense, since the web socket was already explicitly closed). This seems to be the cause of the crash - _WebSocketFree checks instance.ws for null, but doesn’t check if it’s undefined.
Our hotfix, until this gets properly resolved in a future update :
function _WebSocketFree(instanceId) {
var instance = webSocketState.instances[instanceId];
if (!instance) return 0;
console.log(`[JSLIB WebSocket] ${JSON.stringify(instance)}`);
// Close if not closed
if (instance.ws !== null && instance.ws !== undefined && instance.ws.readyState < 2)
instance.ws.close();
// Remove reference
delete webSocketState.instances[instanceId];
return 0;
}
Now, messing with the generated js code is not ideal and we are not aware of all potential side effects.
Also, this forces us to apply the fix manually after every build.
We are launching our game in a couple weeks, so I guess we will have to stick to that solution for the time being. It would be great if this fix could be shipped in the next update for the relevant package.
PS : enabling WebAssembly tables is also an issue with that bit in particular, since there are functions related to that WebSocket conundrum that seem to still be called via the legacy Emscripten dynCall.
To make it work with WebAssembly tables enabled, we applied another fix that is explained in that thread (remapping via a .jspre plugin) : makeDynCall replacing dynCall_ in Unity 6?