emscripten-core / emscripten-core/emscripten

UBSan function pointer mismatch reporting not working

Open
#26,600 5 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

Taking the example from

https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html#working-around-function-pointer-issues

It generates a nice error in a native build:

```
$ clang-19 -fsanitize=undefined a.cpp
$ ./a.out
voidReturn: hello world
a.cpp:22:5: runtime error: call to function intReturn(char const*) through pointer to incorrect function type 'void (*)(const char *)'
(a.out+0x31b68): note: intReturn(char const*) defined here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior a.cpp:22:5
intReturn: hello world
voidReturnNoParam:
```

However, in wasm it doesn't:

```
$ ./emcc a.cpp -g -fsanitize=undefined
$ nodejs a.out.js
voidReturn: hello world
wasm://wasm/a.out.wasm-00a00baa:1

RuntimeError: null function or function signature mismatch
at a.out.wasm.callFunctions(void (* const*)(char const*), unsigned long) (wasm://wasm/a.out.wasm-00a00baa:wasm-function[36]:0xdbb)
at a.out.wasm.__original_main (wasm://wasm/a.out.wasm-00a00baa:wasm-function[37]:0xee2)
at a.out.wasm.main (wasm://wasm/a.out.wasm-00a00baa:wasm-function[42]:0xfb4)
at a.out.js:545:12
at callMain (a.out.js:4310:15)
at doRun (a.out.js:4352:24)
at run (a.out.js:4362:5)
at removeRunDependency (a.out.js:742:7)
at receiveInstance (a.out.js:632:5)
at receiveInstantiationResult (a.out.js:648:12)

Node.js v22.22.0
```

UBSan just doesn't do anything here, and we get the low-level error.

I wonder if the issue is that UBSan checks this *after* the call, that is, each function prologue checks if it was indirect-called, and it knows its signature, and reports any mismatch. That seems plausible, and then it would not work in wasm since we trap *before* we reach that code. However, if so, then I'd expect our function pointer cast emulation to fix things, as it avoids the low-level trap, but UBSan's check should still be there (since we do this after UBSan runs), and it doesn't:

```
$ ./emcc a.cpp -g -fsanitize=undefined -sEMULATE_FUNCTION_POINTER_CASTS
$ nodejs a.out.js
voidReturn: hello world
intReturn: hello world
voidReturnNoParam:
```
The program just runs ok, with no report from UBSan despite the undefined behavior.

If we get UBSan working here, it could make debugging this a lot easier for people.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.