Skip to content

__setitimer_js is always included in the glue code #26038

@valadaptive

Description

@valadaptive

Please include the following in your bug report:

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 4.0.22 (0f3d2e62bccf8e14497ff19e05a1202c51eb0c65)
clang version 22.0.0git (https:/github.com/llvm/llvm-project c7706d9472fe880ba1d3418919ad4185710c9559)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/va_erie/Projects/emsdk/upstream/bin

When compiling even the simplest library, the __setitimer_js function is always included in the glue code and imported into the WebAssembly module:

var __setitimer_js = (which, timeout_ms) => {
  // First, clear any existing timer.
  if (timers[which]) {
    clearTimeout(timers[which].id);
    delete timers[which];
  }
  // A timeout of zero simply cancels the current timeout so we have nothing
  // more to do.
  if (!timeout_ms) return 0;
  var id = setTimeout(() => {
    delete timers[which];
    callUserCallback(() => __emscripten_timeout(which, _emscripten_get_now()));
  }, timeout_ms);
  timers[which] = {
    id,
    timeout_ms
  };
  return 0;
};

// ...

var wasmImports = {
  /** @export */ c: __abort_js,
  /** @export */ b: __emscripten_runtime_keepalive_clear,
  /** @export */ a: __setitimer_js,
  /** @export */ d: _proc_exit
};

This happens even if we don't call any functions that use timers, or even call libc functions at all. Simply linking to libc is sufficient to cause __setitimer_js to end up in the glue code.

I think this is caused by a circular dependency. The setitimer libc function calls _emscripten_timeout, which calls the JS-side _setitimer_js. This adds a dependency on the _setitimer_js function from libc.

Then on the JS side, _setitimer_js calls back into the WASM-side _emscripten_timeout, adding a dependency on it. Because we have a JS-side dependency on _emscripten_timeout, it cannot be DCE'd by the linker. Therefore, simply by importing libc, we end up including a bunch of timer glue code that is never actually called.

See also #22534.


You can reproduce this by creating some really simple C code:

int add(int a, int b) {
    return a + b;
}

And compiling it like so:

emcc \
    -s MODULARIZE \
    -s EXPORT_ES6 \
    -s EXPORT_NAME=createAdd \
    -s EXPORTED_FUNCTIONS='["_add"]' \
    -s MAIN_MODULE=0 \
    -s ENVIRONMENT=web \
    -s MINIMAL_RUNTIME=1 \
    -o add.js \
    -Oz \
    -flto \
    --minify=0 \
    --no-entry \
    add.c

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions