emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.35k stars 3.25k forks source link

new (std::nothrow) with optimizations exhibiting some strange behavior #22149

Closed phuhgh closed 3 days ago

phuhgh commented 4 days ago

Version of emscripten/emsdk: emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.61 (67fa4c16496b157a7fc3377afd69ee0445e8a6e3) clang version 19.0.0git (https:/github.com/llvm/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520) Target: wasm32-unknown-emscripten Thread model: posix InstalledDir: D:\pro\deps\emsdk\upstream\bin

Failing command line in full: em++ test_nothrow_new.cpp -sENVIRONMENT=node -sEXIT_RUNTIME=1 -sINITIAL_MEMORY=18MB -sALLOW_MEMORY_GROWTH=1 -sABORTING_MALLOC=0 -sMAXIMUM_MEMORY=18MB -o test_nothrow_new.js -O3 && node test_nothrow_new.js

I was trying out the nothrow new that got implemented with https://github.com/emscripten-core/emscripten/issues/20132, and I've been left quite puzzled regarding the behavior with vs without optimizations. I've reworked one of your unit tests to help show this (test\core\test_nothrow_new.cpp).

#include <cstdio>
#include <new>

int main() {
  char* data = new (std::nothrow) char[20 * 1024 * 1024];
  // uncomment this line and the test passes (with optimizations off it will pass regardless)
  //  printf("data: %p\n", data);
  if (data == nullptr) {
    printf("success\n");
  } else {
    printf("fail\n");
  }
  return 0;
}

Is this expected behavior? FWIW running this with MSVC (requesting uint64 max) seems to yields a nullptr in all combinations, I could check clang later if it helps.

Thanks for the work on emscripten, it's a cool project 👍

sbc100 commented 4 days ago

I think what is happening here is that the optimizer is able to completely remove the call to new in cases where the result is never used.

In this case the compiler just assumes that new succeeds since the value of the data is never used. It probably decides that it only actually needs to call new if the result is used.

phuhgh commented 4 days ago

Yeah that was my guess. I mean this only came up in unit tests around OOM handling (easy to work around by actually using the created values).

I don't see it as a dealbreaker in using it, but I thought it at least surprising enough to mention, if for no other reason hopefully the next person searching for this can skip straight to the workaround 😄

phuhgh commented 3 days ago

Finally got around to checking other compilers, GCC is consistent with MSVC, clang behaves as per the OP. This doesn't appear to be an emscripten issue.

sbc100 commented 3 days ago

Perhaps there is a clang flag to disable this behavior? Maybe -fno-builtin would do it?

In any case closing this now since this is just normal clang behaviour. Feel free to re-open if you disagree.