Skip to content

pthread_create detected as undefined symbol with side module + -fexception + -O3 #14896

Description

@thierrytrietlam

Hello,

When creating a side module with the pthread option, an assertion occured during the loading of the side module when compilation includes the -fexceptions and -O3. In my project, the -fexceptions is mandatory so I did the small example to check this problem.

Compilation:

REM Step 1: Remove previous compilation
CALL rm *.html *.wasm *.js *.o *.tmp*

REM Step 2: Compilation Options
CALL em++ -c Side.cpp -pthread -fPIC -fexceptions -O3 -o foo2.o
CALL em++ -c Main.cpp -pthread -fPIC -fexceptions -O3 -o Main.o

REM Step 3: Create WASM libraries using SIDE_MODULE
CALL em++ foo2.o -s SIDE_MODULE=1 -s EXPORT_ALL=1 -pthread -fPIC -o foo2.wasm

REM Step 4: Execute without Side_Module
CALL em++ -pthread -s MAIN_MODULE=1 -s PROXY_TO_PTHREAD -s ALLOW_MEMORY_GROWTH=1 -fPIC -s EXIT_RUNTIME=1 Main.o -s RUNTIME_LINKED_LIBS="['foo2.wasm']" -o Test.html

The callstack is the following:

Test.html:1246 Assertion failed: Missing signature argument to addFunction: function _pthread_create(pthread_ptr, attr, start_routine, arg) {
 if (typeof SharedArrayBuffer === "undefined") {
  err("Current environment does not support SharedArrayBuffer, pthreads are not available!");
  return 6;
...
printErr	@	Test.html:1246
abort	@	Test.js:1273
assert	@	Test.js:655
addFunctionWasm	@	Test.js:512
reportUndefinedSymbols	@	Test.js:2425
(anonymous)	@	Test.js:2455
Promise.then (async)		
preloadDylibs	@	Test.js:2453
run	@	Test.js:48460
runCaller	@	Test.js:48421
removeRunDependency	@	Test.js:1256
receiveInstance	@	Test.js:1379
receiveInstantiationResult	@	Test.js:1389
Promise.then (async)		
(anonymous)	@	Test.js:1409
Promise.then (async)		
instantiateAsync	@	Test.js:1407
createWasm	@	Test.js:1428
(anonymous)	@	Test.js:32966

I investigated the pthread_create appearances in the binary file (Test.wasm) and saw these two lines:

(func $env.pthread_create (;16;) (import "env" "pthread_create") (param i32 i32 i32 i32) (result i32))

(global $GOT.func.pthread_create (;14;) (import "GOT.func" "pthread_create") (mut i32))

The second one will fill the GOT table which is why pthread_create appears as an undefined symbol.

Result:
image

If I remove the -O3 option, it will return the heap memory area (address zero)! issue.
This is the current of my analysis, any suggestions to help me solve this problem are welcomed.

My snippet code:
Main.cpp

int side_main();
int main()
{

	side_main();
	return 0;
}

Side.cpp

// thread example
#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <pthread.h>
#include <sstream>
#include <unistd.h> //sleep
#define NUM_THREADS 5

void foo() 
{
  std::cout <<"Check foo()"<< std::endl;
}

void bar(int x)
{
  std::cout <<"Check bar(x)"<< std::endl;
}

int side_main() 
{
  std::thread first (foo);     // spawn new thread that calls foo()
  std::thread second (bar,0);  // spawn new thread that calls bar(0)
  std::cout << "main, foo and bar now execute concurrently...\n";
  // synchronize threads:
  first.join();                // pauses until first finishes
  second.join();               // pauses until second finishes
  std::cout << "foo and bar completed.\n";
  return 0;
}

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