webui-dev / webui

Use any web browser or WebView as GUI, with your preferred language in the backend and modern web technologies in the frontend, all in a lightweight portable library.
https://webui.me
MIT License
2.63k stars 157 forks source link

bug: Heap corruption detected, free list is damaged #231

Closed 7flash closed 10 months ago

7flash commented 10 months ago

To reproduce,

1) create second.ts

import { WebUI } from "./deno-webui/mod.ts";

const firstWindow = new WebUI();

firstWindow.bind('saveScene', async (inputData) => {
  try {
    await new Promise(resolve => setTimeout(resolve, 1000));
    return { success: true, data: `${new Date().toLocaleTimeString()}` };
  } catch (error) {
    return { success: false, error: error.message };
  }
});

try {
  await firstWindow.show(`<html>${new Date().toLocaleTimeString()}<script src="/webui.js"></script></html>`);
} catch (err) {
  console.error(err);
}

await WebUI.wait();

2) deno run --allow-all --unstable second.ts

3) open devtools

4) execute

window.webui.call('saveScene', '')

5) it returns result but then immediately crashes app with an error

deno(92824,0x7ff85638b640) malloc: Heap corruption detected, free list is damaged at 0x6000029d8260
*** Incorrect guard value: 105553182089216
deno(92824,0x7ff85638b640) malloc: *** set a breakpoint in malloc_error_break to debug
Abort trap: 6
7flash commented 10 months ago
result 2
result 3
deno(90664,0x7ff85638b640) malloc: Heap corruption detected, free list is damaged at 0x6000027a8160
*** Incorrect guard value: 105553155722048
deno(90664,0x7ff85638b640) malloc: *** set a breakpoint in malloc_error_break to debug
Abort trap: 6
7flash commented 10 months ago

updated original comment with simpler example to reproduce, following is original code

import { WebUI } from "./deno-webui/mod.ts";

const firstWindow = new WebUI();

firstWindow.bind('executeDeno', async (inputData) => {
  try {
    let { code, input } = JSON.parse(inputData.data);

    code = code.replace(/\s+/g, ' ')

    let fn = new Function('return ' + code)();

    let result = await fn(input);

    console.log('result', result);

    return { success: true, data: result };
  } catch (error) {
    return { success: false, error: error.message };
  }
});

try {
  await firstWindow.show(`<html>${new Date().toLocaleTimeString()}<script src="/webui.js"></script></html>`);
} catch (err) {
  console.error(err);
}

await WebUI.wait();
window.webui.call('executeDeno', JSON.stringify({
    input: {},
    code: `
        async function it(input) {
        await new Promise(resolve => setTimeout(resolve, 100));
        return 2;
        }
    `
}))
7flash commented 10 months ago

Temporary solution:

import { WebUI } from "./deno-webui/mod.ts";

const firstWindow = new WebUI();

let taskId = 0;
firstWindow.bind('saveScene', () => {
  taskId++;
  (async () => {
    await new Promise(resolve => setTimeout(resolve, 100));
    firstWindow.script(`alert('${taskId} completed at ${new Date().toLocaleTimeString()}')`);
  })();
  return { taskId };
});

try {
  await firstWindow.show(`<html>${new Date().toLocaleTimeString()}<script src="/webui.js"></script></html>`);
} catch (err) {
  console.error(err);
}

await WebUI.wait();
7flash commented 10 months ago

another weird issue with temporary solution, if I remove setTimeout delay it only triggers once (does not trigger when repeatedly calling it from devtools)

import { WebUI } from "./deno-webui/mod.ts";

const firstWindow = new WebUI();

let taskId = 0;
firstWindow.bind('saveScene', () => {
  taskId++;
  (async () => {
    firstWindow.script(`alert('${taskId} completed at ${new Date().toLocaleTimeString()}')`);
  })();
  return { taskId };
});

try {
  await firstWindow.show(`<html>${new Date().toLocaleTimeString()}<script src="/webui.js"></script></html>`);
} catch (err) {
  console.error(err);
}

await WebUI.wait();

but this works

  setTimeout(async () => {
    firstWindow.script(`alert('${currentTaskId}')`);
  }, 0);
hassandraga commented 10 months ago

Thank you for the report. I tested it with the latest commit, which seems to be solved. I can't reproduce the issue.