Webassembly C program crashing at malloc - c

I'm working on a Javascript/web module bundler program that is written in C and a bit of JavaScript. I keep having a problem with the program where the program will randomly crash at a random malloc call in a random function. It only occurs when I use it on a more complicated project with far more files and will work fine if used on a smaller project. I've had errors with malloc and free that were being caused by memory leaks/errors in other parts of the program but as far as I can tell there is nothing wrong this time that is noticeable.
This is the error message that occurs:
RuntimeError: memory access out of bounds
at dlmalloc (wasm://wasm/007a3c2a:wasm-function[339]:0x7db59)
at ReadDataFromFile (wasm://wasm/007a3c2a:wasm-function[114]:0x4cfd8)
at BundleFile (wasm://wasm/007a3c2a:wasm-function[128]:0x55e36)
at BundleFiles (wasm://wasm/007a3c2a:wasm-function[130]:0x6b9fb)
at /mnt/c/Users/redstarbird/Documents/Projects/ArrowStack/Build/CFunctions.js:985:22
at Object.ccall (/mnt/c/Users/redstarbird/Documents/Projects/ArrowStack/Build/CFunctions.js:5328:22)
at /mnt/c/Users/redstarbird/Documents/Projects/ArrowStack/src/ArrowPack.js:104:24
The function that it crashes in looks like this:
char EMSCRIPTEN_KEEPALIVE *ReadDataFromFile(char *path)
{ // returns contents of file
printf("path: %s\n", path);
FILE *filePTR = fopen(path, "r");
if (filePTR == NULL)
{
printf("Error opening file %s\n", path);
return NULL;
}
fseek(filePTR, 0, SEEK_END); // seek to end of file
long int length = ftell(filePTR); // get length of file
fseek(filePTR, 0, SEEK_SET); // go back to start of file
char *buffer = malloc(length + 1); // This is where it crashes
if (buffer == NULL)
{
printf("Error creating buffer\n");
exit(1);
}
int currentChar = 0;
do
{
if (feof(filePTR))
{
break;
}
buffer[currentChar] = fgetc(filePTR);
currentChar++;
} while (1);
fclose(filePTR);
buffer[currentChar - 1] = '\0';
return buffer;
}
The project is compiled using this command:
emcc --no-entry -s INITIAL_MEMORY=128mb -Wl,--export=__heap_base -Wl,--export=__data_end -Wl,--export=malloc -Wl,--export=free -sENVIRONMENT=node --profiling -sRUNTIME_DEBUG=1 -fsanitize=undefined -sLLD_REPORT_UNDEFINED -g3 -sSTACK_OVERFLOW_CHECK=2 -sASSERTIONS=2 src/Main.c src/C/cJSON/cJSON.c src/DependencyGraph/DependencyGraph.c ./src/C/StringRelatedFunctions.c ./src/Regex/RegexFunctions.c ./src/DependencyGraph/FindDependencies.c ./src/SettingsSingleton/settingsSingleton.c ./src/C/ProblemHandler.c ./src/C/TextColors.c ./src/C/FileHandler.c ./src/C/IntFunctions.c ./src/Minifiers/HTMLMinifier.c ./src/C/FileTypesHandler.c ./src/C/Stack.c ./src/C/BundleFiles.c ./src/C/ProgressBar.c ./src/C/StringShiftHandler.c ./src/Minifiers/JSMinifier.c -s EXPORT_ES6=0 -s MODULARIZE -s USE_ES6_IMPORT_META=0 -s EXPORTED_RUNTIME_METHODS=["ccall"] -s NODERAWFS=1 -sBINARYEN=1 -sEXIT_RUNTIME=1 -sALLOW_MEMORY_GROWTH -o Build/CFunctions.js
The javascript code to initialise the webassembly looks like this:
#!/usr/bin/env node
"use strict";
// js wrapper for arrowpack for NPM
const fs = require("fs");
const path = require("path");
const chalk = require("chalk");
const settingsSingleton = require("./SettingsSingleton/settingsSingleton");
const DirFunctions = require("./js/DirFunctions");
const wasm_exec = require("../Build/wasm_exec.js");
const CFunctionFactory = require("../Build/CFunctions.js");
const go = new Go();
// const Sleep = require("../src/js/Sleep");
const { mkdirIfNotExists } = require("./js/DirFunctions.js");
var StartTime = performance.now();
const argv = require("yargs/yargs")(process.argv.slice(2))
.option("c", {
alias: "config-path",
describe: "Path to config file if not in working directory",
type: "string"
})
.help().argv;
var CONFIG_FILE_NAME = "ArrowPack-config.json"
if (argv.c) { CONFIG_FILE_NAME = path.join(argv.c, CONFIG_FILE_NAME) } else { console.log("no custom file thingy"); }
var rawconfigData = null;
if (fs.existsSync(CONFIG_FILE_NAME)) { rawconfigData = fs.readFileSync(CONFIG_FILE_NAME, "utf8"); }
var temp;
const Settings = new settingsSingleton(rawconfigData);
if (Settings.getValue("largeProject") === false) {
temp = DirFunctions.RecursiveWalkDir(Settings.getValue("entry")); // eventually add pluginAPI event here
} else {
let RecursiveWalkDirWASM = fs.readFileSync("../Build/RecursiveWalkDir.wasm"); const { WebAssembly } = require("wasi");
let compiledWalkDirWASM = WebAssembly.compile(wasm);
let InstanceWalkDirWASM = WebAssembly.instantiate(compiledWalkDirWASM);
const { InstanceWalkDirWASMExports } = instance;
temp = InstanceWalkDirWASMExports.walk_dir(Settings.getValue("entry"));
}
var WalkedFiles = temp.Files;
var WalkedDirs = temp.Directories;
console.log(WalkedDirs);
if (WalkedDirs) {
WalkedDirs.forEach(Dir => {
console.log(chalk.red(Dir));
var tempDir = Settings.getValue("exit") + Dir.substring(Settings.getValue("entry").length);
console.log(chalk.yellowBright(tempDir));
DirFunctions.mkdirIfNotExists(tempDir);
//DirFunctions.mkdirIfNotExists(Dir);
});
}
DirFunctions.mkdirIfNotExists("ARROWPACK_TEMP_PREPROCESS_DIR");
var AbsoluteFilesCharLength = 0;
var WrappedWalkedFiles = "";
if (WalkedFiles && WalkedFiles.length > 0) { // Paths are wrapped into one string because passing array of strings from JS to C is complicated
WalkedFiles.forEach(FilePath => { WrappedWalkedFiles += FilePath + "::"; console.log(chalk.bold.blue(FilePath)); AbsoluteFilesCharLength += FilePath.length; });
console.log(chalk.red(WalkedFiles.length));
var StructsPointer;
CFunctionFactory().then((CFunctions) => {
CFunctions._CheckWasm();
CFunctions._InitFileTypes();
for (let k in Settings.settings) {
if (CFunctions.ccall(
"SendSettingsString",
"number",
["string"],
[k]
) != 1) {
throw "Error sending Wasm settings string: " + k;
}
console.log(chalk.bold.blue(k));
// Gives time to apply settings
if (CFunctions.ccall(
"SendSettingsString",
"number",
["string"],
[Settings.settings[k].toString()]
) != 1) {
throw "Error sending Wasm settings string: " + Settings.settings[k];
}
console.log(chalk.bold.blue(Settings.settings[k]));
// Also gives time to apply settings
}
var Success;
// StructsPointer = CFunctions._CreateTree(allocateUTF8(WrappedWalkedFiles), WalkedFiles.length, AbsoluteFilesCharLength); // Need to get this working eventually for faster speed but couldn't work out allocateUTF8
StructsPointer = CFunctions.ccall(
"CreateGraph",
"number",
["string", "number"],
[WrappedWalkedFiles, WalkedFiles.length]
);
Success = CFunctions.ccall(
"BundleFiles",
"number",
["number"],
[StructsPointer]
);
if (Success === 1 || Success === 0) {
fs.rm("ARROWPACK_TEMP_PREPROCESS_DIR", { recursive: true }, (err) => {
if (err) { console.error(err); } else {
console.log("Sucessfully removed temporary preprocess directory");
}
});
DirFunctions.DeleteDirectory(); //CFunctions.ccall("PrintTimeTaken", "void", ["number", "number"], [StartTime, performance.now()]); // Not working for some reason
console.log(chalk.magentaBright("Bundling files completed in " + (performance.now() - StartTime) / 1000 + " seconds"));
}
});
// console.log("\n\nBuild completed in" + (EndTime - StartTime) / 1000 + " seconds!\n\n\n"); // Need to get Wasm code to run this because Wasm code seems to be non-blocking
/*
WebAssembly.instantiateStreaming(DependencyTreeWasmBuffer, DependencyTreeMemory).then((instance) => {
StructsPointer = instance.ccall(
"CreateTree",
"number",
["string", "number", "string"],
[WrappedWalkedFiles, WalkedFiles.length, settings.getValue("entry"), settings.getValue("exit")]
)
});
var GoWASMFileHandler;
const goWASM = fs.readFileSync("../Build/FileHandler.wasm");
WebAssembly.instantiate(goWASM, go.importObject).then(function (obj) {
GoWASMFileHandler = obj.instance;
go.run(GoWASMFileHandler);
GoWASMFileHandler.exports.HandleFiles(StructsPointer, settings.getValue("entry"));
});*/
}
The full code for the project is at https://github.com/redstarbird/arrowpack. Any help would be appreciated because I'm very stuck as to how to fix this.

Related

ReactJS file upload Axios

I am having form with 4 file upload fields, that users can submit up to 4 images.
I am adding files to array, loop and upload to server with PHP.
Now everything seams to be working fine.. but returned image names (I am using those to store in DB) are not in the same order as I am uploading them:
Here is example of code:
if (postImage1 !== null) {
postImagesArray.push(postImage1);
}
if (postImage2 !== null) {
postImagesArray.push(postImage2);
}
if (postImage3 !== null) {
postImagesArray.push(postImage3);
}
if (postImage4 !== null) {
postImagesArray.push(postImage4);
}
//Loop Array and make upload......
var startCount = 1;
var endCount = postImagesArray.length;
for (var i = 0; i < postImagesArray.length; i++) {
var currentImage = postImagesArray[i];
//##### UPLOADING IMAGE ###########
try {
var base_url = 'https://##############.com/uploadImage.php';
var fd = new FormData();
fd.append('avatar', currentImage, 'post.jpg');
axios.post(base_url, fd).then((res) => {
console.log(res);
if (res.data.status === 'success') {
let fileConstruct =
'https://############.com/' +
res.data.fileName +
'?fit=crop&w=840&q=80';
uploadImagesArray.push(fileConstruct);
} else {
// there was an error with file upload... revert to default...
console.log('No error but no image either......');
}
if (startCount == endCount) {
uploadImagesConstruct();
}
startCount++;
});
} catch (err) {
//console.error(err);
console.log(
'There was an error uploading file to the web server: ' + err
);
if (startCount == endCount) {
uploadImagesConstruct();
}
}
Interesting thing is, images are mixed up always in the same order... (so it is not random), instead of returned image1,image2,image3,image4 I am getting image3, image2, image4, image1....If I post only 2 images it is image2,image1.... so first image is always returned last.....
Can anybody see what I am doing wrong..
Thanks!!!!
If anyone need this in the future....
I simply added underscore and postion in the loop "_i" before ".jpg" when I am constructing file names..
fd.append('avatar', currentImage, 'post.jpg');
now is:
fd.append('avatar', currentImage, `post_${i}.jpg`);
and since I am putting all records in the array
uploadImagesArray.push(fileConstruct);
I just resorted it.. by the numbers I added..
uploadImagesArray.sort(function(x, y) {
var xp = x.substring(x.lastIndexOf('_') + 1, x.lastIndexOf('.jpg'));
var yp = y.substring(y.lastIndexOf('_') + 1, y.lastIndexOf('.jpg'));
return xp == yp ? 0 : xp < yp ? -1 : 1;
});

How to fix 'HTML5 currentTime always sets to zero'

I am building a videoplayer in reactjs.I have my custom sliderbar.When I click on the sliderbar,I am getting the value of the sliderbar and calculating current time of the video and setting the currenttime using document.getElementById('video').currentTime = value.
But each time when I give an input to sliderbar,the video current time is setted to 0.
But this works fine in firefox with a warning message "The Operation was aborted"
It not working in chrome.
const pos = this.seek_bar.value;
this.video = document.getElementById("video");
let new_time = (pos / 100) * this.video.duration;
if (!isNaN(new_time)) this.video.currentTime = new_time;
this.video.addEventListener("timeupdate", () => {
let value = (this.video.currentTime / this.video.duration) * 100;
if (!isNaN(value)) {
this.seek_bar.value = value;
}
});
I want the chrome to set the current time I provide.Please help me to solve this.
Got It.
The problem was with streaming the video from server.
Changed the existing code to
video(req, res) {
const videoPath = req.query.videoPath;
const stat = fs.statSync(videoPath);
const fileSize = stat.size;
const range = req.headers.range;
if (range) {
const parts = range.replace(/bytes=/, "").split("-");
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunksize = end - start + 1;
const file = fs.createReadStream(videoPath, { start, end });
const head = {
"Content-Range": `bytes ${start}-${end}/${fileSize}`,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4"
};
res.writeHead(206, head);
file.pipe(res);
} else {
const head = {
"Content-Length": fileSize,
"Content-Type": "video/mp4"
};
res.writeHead(200, head);
fs.createReadStream(videoPath).pipe(res);
}
}

Not able to use custom functions in webpack with require

I am creating a progressive web app using react and webpack.
I have successfully configured everything and able to start the development.
Now, i have many helper functions like :
function getCookie(name) {
var start = document.cookie.indexOf(name + "=");
var len = start + name.length + 1;
if ((!start) && (name != document.cookie.substring(0, name.length))) {
return null;
}
if (start == -1) return null;
var end = document.cookie.indexOf(';', len);
if (end == -1) end = document.cookie.length;
return unescape(document.cookie.substring(len, end));
}
So, for this i have created another js file : helper.jsx.
Now my helper.js contains the above function as it is. Now i want to use the above function in another react component.
I am doing a require in my component :
var helper = require("helper");
and trying to call the function using :
helper.getCookie('user');
Which is giving me helper.getCookie is not a defined.
Please tell me how can i create a helper js and use the functions of helper js in my react components.
You need to export the function using module.exports:
function getCookie(name) {
var start = document.cookie.indexOf(name + "=");
var len = start + name.length + 1;
if ((!start) && (name != document.cookie.substring(0, name.length))) {
return null;
}
if (start == -1) return null;
var end = document.cookie.indexOf(';', len);
if (end == -1) end = document.cookie.length;
return unescape(document.cookie.substring(len, end));
}
module.exports = {
getCookie: getCookie
};

screeps.com: simple script not working, issue with bi-dimensional array

I get the following error from the console: "TypeError: Cannot read property '0' of undefined", it has something to do with the array but I cannot find the mistake.
module.exports =
{
create_creeps: function()
{
var aHarvester = [[TOUGH,TOUGH, MOVE, CARRY, WORK, MOVE]["harvester"]];
Spawn.prototype.createMyCreep = function(aCreep,sRole) {
if (!Game.spawns.Spawn1.spawning){
var nameCount = 0;
var name = null;
while(name == null)
{
nameCount++;
var tryName = sRole + nameCount;
if(Game.creeps[tryName] == undefined)
name = tryName;
}
var dbg= this.canCreateCreep(aCreep, name);
if(dbg == OK) {
console.log("Creating creep " + sRole);
return this.createCreep(aCreep , name,{ role:sRole });
} else {
console.log("error "+dbg+" "+sRole);
}
}
};
Game.spawns.Spawn1.createMyCreep(aHarvester[0],aHarvester[1][0]);
};
}
Please separate arrays with a comma
So
[[TOUGH,TOUGH, MOVE, CARRY, WORK, MOVE]["harvester"]]
Should be
[[TOUGH,TOUGH, MOVE, CARRY, WORK, MOVE],["harvester"]]

iNotify how to detect move-out

Hi there I am using iNotify to detect changes in a directory. The flags I am using are IN_CLOSE_WRITE | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE
I am trying to differentiate between a IN_MOVED_FROM when renaming, and the IN_MOVED_FROM when a file is moved out of the folder.
I thought to check if the cookie field is not 0 when user moved the file out. As I thought cookie was only for rename procedure. However even when I move the file out of the directory it still has a cookie.
I also though to check for IN_MODIFY as I was hoping that would be there on rename but not on move, but its not there for either.
Does anyone have any ideas on how to detect if it was just "moved-out" or it is the "renamed-from-oldfilename"?
Thanks
You need to check for the IN_MOVED_FROM event and a following IN_MOVED_TO event. If the cookie is the same, the file has been renamed in the same folder. If you don't receive a IN_MOVED_TO event with the same cookie, the file has been moved outside of the watched folder.
I applied the logic mention by #hek2mgl and its working so big thanks to him. This is js-ctypes code:
while (true) {
let length = ostypes.API('read')(fd, buf, count);
length = parseInt(cutils.jscGetDeepest(length));
if (length == -1) {
throw new Error({
name: 'os-api-error',
message: 'Failed to read during poll',
uniEerrno: ctypes.errno
});
} else if (!length==0) {
// then its > 0 as its not -1
// something happend, read struct
let FSChanges = [];
var i = 0;
var numElementsRead = 0;
length = parseInt(cutils.jscGetDeepest(length));
var _cache_aRenamed_local = {}; // local means per buffer
do {
let iHoisted = i;
numElementsRead++;
var casted = ctypes.cast(buf.addressOfElement(iHoisted), ostypes.TYPE.inotify_event.ptr).contents;
var fileName = casted.addressOfField('name').contents.readString();
var mask = casted.addressOfField('mask').contents;
var len = casted.addressOfField('len').contents;
var cookie = cutils.jscGetDeepest(casted.addressOfField('cookie').contents)
var wd = casted.addressOfField('wd').contents;
var aEvent = convertFlagsToAEventStr(mask);
if (aEvent == 'renamed-to') {
if (cookie in _cache_aRenamed_local) { // assuming that renamed-from must happen before rename-to otherwise its a added
if (_cache_aRenamed_local[cookie].aExtra.aOSPath_parentDir_identifier == wd) { // aOSPath_parentDir_identifier is a wd if its different then the current wd then it was added/removed from that watched dir
var rezObj = {
aFileName: fileName,
aEvent: 'renamed',
aExtra: {
nixInotifyFlags: mask, // i should pass this, as if user did modify the flags, they might want to figure out what exactly changed
aOSPath_parentDir_identifier: wd,
aOld: {
aFileName: _cache_aRenamed_local[cookie].aFileName,
aExtra: {
nixInotifyFlags: _cache_aRenamed_local[cookie].aExtra.nixInotifyFlags
}
}
}
}
FSChanges.push(rezObj);
} else {
// the one in cache was removed from its parent folder, this one here was added to parent folder. so this is detect as file moved from one watched dir to another watched dir
if (_cache_aRenamed_local[cookie].aFileName != fileName) {
console.error('whaaaaa wd\'s are differnt and got renamed-to so names should be same');
_cache_aRenamed_local[cookie].aEvent = 'haaa names are different?? im just going to say REMOVED as a guess i have never encoutnered this situation yet and i dont think we ever should';
FSChanges.push(_cache_aRenamed_local[cookie]);
} else {
_cache_aRenamed_local[cookie].aEvent = 'removed';
FSChanges.push(_cache_aRenamed_local[cookie]);
}
}
delete _cache_aRenamed_local[cookie];
} else {
var rezObj = {
aFileName: fileName,
aEvent: 'added',
aExtra: {
aOSPath_parentDir_identifier: wd
}
}
FSChanges.push(rezObj);
}
} else if (aEvent == 'renamed-from') {
var rezObj = {
aFileName: fileName,
aEvent: aEvent,
aExtra: {
aOSPath_parentDir_identifier: wd
}
}
_cache_aRenamed_local[cookie] = rezObj;
} else {
var rezObj = {
aFileName: fileName,
aEvent: aEvent,
aExtra: {
aOSPath_parentDir_identifier: wd
}
}
FSChanges.push(rezObj);
}
if (len == 0) {
break;
};
i += nixStuff.sizeField0 + nixStuff.sizeField1 + nixStuff.sizeField2 + nixStuff.sizeField3 + parseInt(len);
} while (i < length);
for (var cookieLeft in _cache_aRenamed_local) {
// whatever is left in _cache_aRenamed_local is `removed` things
_cache_aRenamed_local[cookieLeft].aEvent = 'removed';
FSChanges.push(rezObj);
}
console.error('loop ended:', 'numElementsRead:', numElementsRead);
if (FSChanges.length > 0) {
return FSChanges;
} // else dont return and continue loop
}
}
I use this function to convert the flags to a string of like renamed-from or renamed-to
function convertFlagsToAEventStr(flags) {
var default_flags = {
IN_CLOSE_WRITE: 'contents-modified',
IN_MOVED_TO: 'renamed-to', // can also be a added
IN_DELETE: 'removed',
IN_MOVED_FROM: 'renamed-from', // can also be a removed
IN_CREATE: 'added'
};
for (var f in default_flags) {
if (flags & ostypes.CONST[f]) {
return default_flags[f];
}
}
return 'UNKNOWN FLAG';
}

Resources