shithub: puzzles

Download patch

ref: 5acce15ed907d29a5575668a09e7d94cf7a36b3f
parent: 6a41c0b7a0c0f8299a86e5d33e7008ced3911924
author: Ben Harris <bjh21@bjh21.me.uk>
date: Tue May 30 12:55:22 EDT 2023

js: pass preferences file from JS to C on the heap, not the stack

The C stack used by Emscripten is quite small, so passing more than a
few klilobytes of data on it tends to cause an overflow.  Current
versions of puzzles will only generate tiny preferences files, but this
might change in future and in any case Puzzles shouldn't crash just
because the preferences in local storage have got corrupted.

To fix this, we now have JavaScript allocate a suitable amount of C heap
memory using malloc() and stick the preferences file in there.

This could plausibly fail if the preferences file were really big, but
that's unlikely since browsers generally limit an origin to about 5 MB
of local storage.  In any case, if malloc() does fail, we'll just ignore
the preferences file, which is probably the right thing to do.

--- a/cmake/platforms/emscripten.cmake
+++ b/cmake/platforms/emscripten.cmake
@@ -49,6 +49,9 @@
   _rescale_puzzle
   # Callback for loading user preferences
   _prefs_load_callback
+  # Functions for allocating and freeing C memory
+  _malloc
+  _free
   # Main program, run at initialisation time
   _main)
 
--- a/emcclib.js
+++ b/emcclib.js
@@ -827,7 +827,13 @@
             var prefsdata =
                 localStorage.getItem(location.pathname + " preferences");
             if (prefsdata !== undefined && prefsdata !== null) {
-                prefs_load_callback(me, prefsdata);
+                var lenbytes = lengthBytesUTF8(prefsdata) + 1;
+                var dest = _malloc(lenbytes);
+                if (dest != 0) {
+                    stringToUTF8(prefsdata, dest, lenbytes);
+                    prefs_load_callback(me, dest);
+                    _free(dest);
+                }
             }
         } catch (error) {
             // Log the error but otherwise pretend the settings were
--- a/emccpre.js
+++ b/emccpre.js
@@ -693,7 +693,7 @@
                                    ['number','number']);
     timer_callback = Module.cwrap('timer_callback', 'void', ['number']);
     prefs_load_callback = Module.cwrap('prefs_load_callback', 'void',
-                                       ['number','string']);
+                                       ['number','number']);
 
     if (resizable_div !== null) {
         var resize_handle = document.getElementById("resizehandle");