Skip to content

Behaviour of new with std::nothrow #20132

Closed
@M-Mueller

Description

@M-Mueller

I'm currently porting some code that uses std::nothrow for allocations. However, if I build without exception support, the application aborts if the allocation fails instead of returning 0.

The issue can be reproduced with the following code:

#include <iostream>
#include <new>

int main() {
  uint8_t *a = new (std::nothrow) uint8_t[(unsigned long)-518344287];

  std::cout << "Result: " << (size_t)a << std::endl;

  return 1;
}

Build with:

em++ main.cpp -o index.html -sALLOW_MEMORY_GROWTH

If I run this in the browser I get:

Cannot enlarge memory, asked to go up to 3776712704 bytes, but the limit is 2147483648 bytes! [index.js:1116:12](http://localhost:8000/index.js)
Cannot enlarge memory, asked to go up to 3776716800 bytes, but the limit is 2147483648 bytes! [index.js:1116:12](http://localhost:8000/index.js)
Aborted(native code called abort()) [index.js:656:6](http://localhost:8000/index.js)
Uncaught RuntimeError: Aborted(native code called abort())
    abort http://localhost:8000/index.js:675
    _abort http://localhost:8000/index.js:1061
    createExportWrapper http://localhost:8000/index.js:705
    callMain http://localhost:8000/index.js:4925
    doRun http://localhost:8000/index.js:4975
    run http://localhost:8000/index.js:4986
    setTimeout handler*run http://localhost:8000/index.js:4982
    runCaller http://localhost:8000/index.js:4910
    removeRunDependency http://localhost:8000/index.js:642
    receiveInstance http://localhost:8000/index.js:842
    receiveInstantiationResult http://localhost:8000/index.js:860
    promise callback*instantiateAsync/< http://localhost:8000/index.js:795
    promise callback*instantiateAsync http://localhost:8000/index.js:787
    createWasm http://localhost:8000/index.js:879
    <anonymous> http://localhost:8000/index.js:4595

If I build with -fexception the code works as expected, i.e. the "Cannot enlarge memory" errors are still there but the program doesn't abort and prints "Result: 0".

I think the problem is in system/lib/libcxx/src/new.cpp: the operator new(size_t size, const std::nothrow_t&) just calls operator new(std::size_t size) internally which always aborts in case of failure.

I agree with the reasons for abort in #11042 for the current behaviour of operator new(std::size_t size). However, I think the std::nothrow variant aborting is not correct. Without exceptions enabled, this is the only method to check whether an allocation failed. Also code that uses this should be aware that it might return 0.

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.44 (bec42dac7873903d09d713963e34020c22a8b
d2d)
clang version 17.0.0 (https://github.com/llvm/llvm-project a8cbd27d1f238e104a5d5ca345d93bc1f4d4ab1f)
Target: wasm32-unknown-emscripten
Thread model: posix

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