Open DoLevi opened 1 year ago
Seems like it must be some kind of memory corruption of the malloc metadata.
Can you trying building without USE_PTHREADS
and SHARED_MEMORY
?
Does it happen at all opt levels (-O0
, -O1
, etc..)?
The program execution fails on the following n-th calls on my machine:
build flags | -O0 |
-O1 |
-O2 |
-O3 |
---|---|---|---|---|
with USE_PTHREADS & SHARED_MEMORY |
2nd call | 2nd call | 2nd call | 2nd call |
without USE_PTHREADS & SHARED_MEMORY |
2nd call | 3rd call | 3rd call | 3rd call |
And if I build with pthreads and the sanitizer I run into:
RuntimeError: memory access out of bounds
at __pthread_getspecific
at __asan::AsanTSDGet()
at __asan::GetCurrentThread()
at __sanitizer::BufferedStackTrace::UnwindImpl(unsigned long, unsigned long, void*, bool, unsigned int)
at malloc
at operator new(unsigned long)
at operator new[](unsigned long)
at // ...
seemingly appearing if the WebAssembly application demands more than a certain amount of memory (in spite of ALLOW_MEMORY_GROWTH=1
).
This occurs for the build command:
emcc -O3 -g -fsanitize=undefined -fsanitize=address -s ASSERTIONS=1 \
-I /libde265 -I /libde265/libde265 \
-s MODULARIZE=1 \
-s EXPORT_ES6=1 \
-s EXPORT_NAME="libde265Coder" \
-o "/dist/$BUILD_NAME.out.js" \
-s WASM=1 \
-s EXPORTED_FUNCTIONS=_malloc,_free \
-s EXPORTED_RUNTIME_METHODS=addFunction,removeFunction,GROWABLE_HEAP_U8 \
-s ALLOW_TABLE_GROWTH=1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s USE_PTHREADS=1 \
-s SHARED_MEMORY=1 \
-s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency \
-pthread \
--cache "/cache" \
/src/libde265_coder.cc /libde265/libde265/*.cc /libde265/libde265/encoder/*.cc /libde265/libde265/encoder/algo/*.cc
A core developer of the library I try to port helped me out so the issue seems solved to me.
It seems there was an issue with said library which they plan to fix because potentially a lot of data is pushed to the stack.
By increasing the stack size (-sSTACK_SIZE=10MB
) the program runs well and as expected in all regards.
I am still wondering though why this is issue is not appearing when using sanitizing (as I'm not an experienced C-developer at all :sweat_smile:).
It's possible that memory layout is a little different when sanitizing, and somehow the problem is avoided by pure luck. But a stack overflow is something I'd expect sanitizers (at least asan) to find, so it is odd...
Stack overload should also be detected by -sASSERTIONS=2
and to a lesser extent -sASSERTIONS=2
Version of emscripten/emsdk: 3.1.32
Failing command line in full: No build-/link-time failure
Full link command and output with
-v
appended: Build & link without sanitize (log here)Expand build command
```bash emcc -O3 -g -v \ -I /libde265 -I /libde265/libde265 \ -s MODULARIZE=1 \ -s EXPORT_ES6=1 \ -s EXPORT_NAME="libde265Coder" \ -o "/dist/$BUILD_NAME.out.js" \ -s WASM=1 \ -s EXPORTED_FUNCTIONS=_malloc,_free \ -s EXPORTED_RUNTIME_METHODS=addFunction,removeFunction \ -s ALLOW_TABLE_GROWTH=1 \ -s INITIAL_MEMORY=134217728 \ -s USE_PTHREADS=1 \ -s SHARED_MEMORY=1 \ -s ASSERTIONS=1 \ -pthread \ --cache "/cache" \ /src/libde265_coder.cc /libde265/libde265/*.cc /libde265/libde265/encoder/*.cc /libde265/libde265/encoder/algo/*.cc ```Build & link with sanitize (log here)
Expand build command
```bash emcc -O3 -g -v -fsanitize=address \ -I /libde265 -I /libde265/libde265 \ -s MODULARIZE=1 \ -s EXPORT_ES6=1 \ -s EXPORT_NAME="libde265Coder" \ -o "/dist/$BUILD_NAME.out.js" \ -s WASM=1 \ -s EXPORTED_FUNCTIONS=_malloc,_free \ -s EXPORTED_RUNTIME_METHODS=addFunction,removeFunction \ -s ALLOW_TABLE_GROWTH=1 \ -s INITIAL_MEMORY=134217728 \ -s USE_PTHREADS=1 \ -s SHARED_MEMORY=1 \ -s ASSERTIONS=1 \ -pthread \ --cache "/cache" \ /src/libde265_coder.cc /libde265/libde265/*.cc /libde265/libde265/encoder/*.cc /libde265/libde265/encoder/algo/*.cc ```The library I try to port to WebAssembly hits a first call to
new slice_segment_header
(Class 2) which succeeds and later a second call to it which causes this Error to be thrown:However when I run with
-fsanitize=address
the error does not appear and the code runs through every call tonew slice_segment_header
successfully.Also, i tried changing the
INITIAL_MEMORY
(to 16MB, 64MB, 128MB) as well asALLOW_MEMORY_GROWTH=1
but the error persists for any of those settings.Class 1, referenced by class 2
```C class ref_pic_set { public: // Lists of pictures that have to be kept in the decoded picture buffer for future // reference and that may optionally be used for prediction in the current frame. // Lists contain the relative POC positions. int16_t DeltaPocS0[MAX_NUM_REF_PICS]; // sorted in decreasing order (e.g. -1, -2, -4, -7, ...) int16_t DeltaPocS1[MAX_NUM_REF_PICS]; // sorted in ascending order (e.g. 1, 2, 4, 7) // flag for each reference whether this is actually used for prediction in the current frame uint8_t UsedByCurrPicS0[MAX_NUM_REF_PICS]; uint8_t UsedByCurrPicS1[MAX_NUM_REF_PICS]; uint8_t NumNegativePics; // number of past reference pictures uint8_t NumPositivePics; // number of future reference pictures // --- derived values --- void compute_derived_values(); uint8_t NumDeltaPocs; // total number of reference pictures (past + future) uint8_t NumPocTotalCurr_shortterm_only; /* Total number of reference pictures that may actually be used for prediction in the current frame. */ void reset(); }; ```Class 2, referencing class 1
```C class slice_segment_header { public: slice_segment_header() { reset(); } de265_error read(bitreader* br, decoder_context*, bool* continueDecoding); de265_error write(error_queue*, CABAC_encoder&, const seq_parameter_set* sps, const pic_parameter_set* pps, uint8_t nal_unit_type); void dump_slice_segment_header(const decoder_context*, int fd) const; void set_defaults(); void reset(); int slice_index; // index through all slices in a picture (internal only) std::shared_ptr