I try to load a file from my local filesystem, which is then loaded into MEMFS (provided by Emscripten) and pass the file name as one argument to a C program which is cross compiled as WebAssembly using Emscripten. When calling the function to load the file I get the error: Uncaught RuntimeError: memory access out of bounds. What am I doing wrong? Are the parameters handed-over incorrectly or is the file access not correct?
C program, has standard main and parameters are passed correctly, loading the file looks like this (in an abstract):
int CLASS main(int argc, const char **argv)
{
...
FILE *ifp;
const char *ifname;
...
// Start - debug code
for (int i = 0; i < argc; i++)
{
// ==> This prints the arguments correctly in the browser console, so the hand-over works.
printf("argv[%d] = %s\n", i, argv[i]);
}
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) != NULL)
{
// Also prints the MEMFS directory structure correctly.
printf("Current working directory: %s\n", cwd);
}
// End - debug code
ifname = argv[arg];
if (!(ifp = fopen(ifname, "rb")))
{
perror(ifname);
continue;
}
...
In JavaScript it's called like this:
async _runProgram(args) {
// Load the emscripten wrapper
this._dcrawModule = await Module();
// Convert the JavaScript array to a C-style null-terminated string array
const paramStrings = args.map((str) => this._dcrawModule.allocateUTF8(str));
// Allocate memory for the array of pointers
const paramArray = this._dcrawModule.stackAlloc((paramStrings.length + 1) * 4);
paramStrings.forEach((strPtr, i) => {
this._dcrawModule.setValue(paramArray + i * 4, strPtr, 'i32');
});
// Null-terminate the array
this._dcrawModule.setValue(paramArray + paramStrings.length * 4, 0, 'i32');
// Call the `_main` method with the parameter array
return this._dcrawModule['_main'](paramStrings.length + 1, paramArray, 0);
}
The file itself is loaded into MEMFS doing the following and then the '_runProgram' function is called:
...
// Create a workspace directory in the emscripten virtual file system and go to it
FS.mkdir('/workspace');
FS.chdir('/workspace');
if (raw_file) {
FS.createDataFile('/workspace/', 'raw_buf', raw_file, true, true);
args.push('/workspace/raw_buf');
//args.push('raw_buf'); //Tried also this and other variants, no success.
}
...
this._runProgram(args);
Does anyone has experience with Emscripten, MEMFS, WebAssembly and opening a file in a C-program? My preference would be to not change the C-program as this is not mine and I want to avoid having to adapt it every time it might be updated in the future (in addition my C knowledge is quite limited :-P) (full c program can be found here: https://dechifro.org/dcraw/dcraw.c)
Flags used to run the emcc compiler are the following:
FLAGS = -O0 \
-s ALLOW_MEMORY_GROWTH=1 \
-s TOTAL_MEMORY=134217728 \
-s NO_EXIT_RUNTIME=1 \
-s FORCE_FILESYSTEM=1 \
--memory-init-file 0 \
-s MODULARIZE=1 \
-s WASM=1 \
-s EXPORT_ES6=1 \
-s EXPORTED_FUNCTIONS="['_main']" \
-s EXPORTED_RUNTIME_METHODS=FS,setValue,stringToUTF8,allocateUTF8,stackAlloc \
-DNODEPS=1