emscripten-core / emscripten-core/emscripten
How to discover what kind of bad function pointer casts occur?
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
Description
Consider the following C++ code that is undefined behavior:
```
a.cpp
```
```c
typedef int (*foo)(void);
typedef void (*bar)(void);
void func()
{
}
int main()
{
foo ptr = (foo)&func;
ptr(); // Undefined behavior in both C & C++, relaxed in x86 native compilers
}
```
Building this code natively with GCC or Clang succeeds and runs fine. However building it with Emscripten with
```
em++ a.cpp -o a.js
```
and running it in node, crashes with
```
:\code\emsdk\emscripten\main\a.js:147
throw ex;
^
RuntimeError: function signature mismatch
at :wasm-function[2]:0x1a2
at main (:wasm-function[3]:0x1c1)
at E:\code\emsdk\emscripten\main\a.js:1564:22
at callMain (E:\code\emsdk\emscripten\main\a.js:2188:15)
at doRun (E:\code\emsdk\emscripten\main\a.js:2245:23)
at run (E:\code\emsdk\emscripten\main\a.js:2260:5)
at runCaller (E:\code\emsdk\emscripten\main\a.js:2166:19)
at removeRunDependency (E:\code\emsdk\emscripten\main\a.js:1473:7)
at receiveInstance (E:\code\emsdk\emscripten\main\a.js:1653:5)
at receiveInstantiationResult (E:\code\emsdk\emscripten\main\a.js:1670:5)
```
which is all as expected, given that Wasm is strict with function pointer signatures, and cannot relax the calling conventions.
Building with `-s EMULATE_FUNCTION_POINTER_CASTS=1` linker flag makes the code also work on Emscripten. However, imagine a user is dealing with a large codebase, and they would want to avoid using the linker flag `-s EMULATE_FUNCTION_POINTER_CASTS=1` due to its runtime overhead.
Unfortunately there is no machinery that would help the user to diagnose where these bad casts occur, since `-s EMULATE_FUNCTION_POINTER_CASTS=1` silently passes such code.
When building without the flag, one gets a crash callstack to the call site where the first bad function pointer cast call is attempted, but this has two issues:
1. the crash does not specify what the mismatch was: what was the signature of the call that was attempted, and what was the actual signature of the function pointer that was being called?
2. if there are multiple such crashes in the application, the program aborts on the first one, leaving the developer to do a tedious fix first crash-rebuild-fix next crash-rebuild-fix next crash... cycle.
It would be nice to have a mode `-s EMULATE_FUNCTION_POINTER_CASTS=2` or similar, which would for each mismatching function pointer signature call, log the callstack and the signatures in question (via e.g. a `warnOnce` style logger), but still keep on executing the program. Would this be doable?
Contributor guide
Assessment
This issue has not been assessed yet.