Skip to content

Signed integer overflow error when using resolvePromise #236

@amoffat

Description

@amoffat

I've created a repo that you can launch in a Codespaces devcontainer on Github, and have confirmed the error is present there: https://github.com/amoffat/quickjs-bug

Desired behavior

The loop runs successfully, with no errors displayed in the console

Actual behavior

Image

It seems like a signed-integer overflow/wraparound error, and indeed, if the iteration num is lowered to 2^15-1, the error is not present.

Boot up the codespace yourself to fiddle with it, but also here is the minimal application code that causes it. Maybe you can see something obvious?

import VARIANT from "@jitl/quickjs-singlefile-browser-release-sync";
import { newQuickJSWASMModuleFromVariant } from "quickjs-emscripten-core";

async function main() {
  console.log("Initializing QuickJS...");

  // Fails
  const iterations = 2 ** 15;
  // Succeeds
  // const iterations = 2 ** 15 - 1;

  // Initialize QuickJS
  const QuickJS = await newQuickJSWASMModuleFromVariant(VARIANT);
  const rt = QuickJS.newRuntime();
  const vm = rt.newContext();

  // Create a dummy host function (necessary to reproduce the bug, but why?)
  using dummy = vm.newFunction("dummy", () => {
    return vm.newNumber(42);
  });

  const jsCode = `
      async function test() {
        return await Promise.resolve(123);
      }
  `;

  // Evaluate the code using QuickJS
  vm.evalCode(jsCode).unwrap();
  using testHandle = vm.getProp(vm.global, "test");

  let i = 0;
  for (i = 0; i < iterations; i++) {
    using clientPromise = vm.callFunction(testHandle, vm.undefined).unwrap();

    // Check promise state and resolve (like the larger project)
    const ps = vm.getPromiseState(clientPromise);

    if (ps.type === "pending") {
      const promise = vm.resolvePromise(clientPromise);
      promise.catch((err) => {
        const error = vm.dump(err);
        console.error("Error in promise:", error);
        err.dispose();
      });
      promise.then((value) => {
        value.dispose();
      });
    } else if (ps.type === "rejected") {
      const error = vm.dump(ps.error);
      throw new Error("Promise was rejected: " + JSON.stringify(error));
    }

    rt.executePendingJobs();
  }

  console.log("Completed iterations:", i);
}

main();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions