Skip to content

Misleading C++ exception handling example #19764

@schaumb

Description

@schaumb

Version of emscripten/emsdk:
Documentation - all version from here.

std::string getExceptionMessage(intptr_t exceptionPtr) {
  return std::string(reinterpret_cast<std::exception *>(exceptionPtr)->what());
}

According to the documentation, this code snippet appears to be a handler function for getExceptionMessage. However, it is much simpler than the current implementation found here.

The documentation also mentions that "this example code will only work for thrown statically allocated exceptions" but in reality, it only works if the exception type is exactly std::exception. It will not work (according to the standard C++) if the exception is a child of std::exception because is_pointer_interconvertible_base_of_v<std::exception, std::[any other std exception]> evaluates to false. Therefore, the reinterpret casting is not safe and results in undefined behavior.

Another issue is that this code can be exploited using the following structure:

struct BaseException {
  virtual ~BaseException() = default;
  virtual const char* hack() const noexcept { return "HACKED"; }
};
struct MyEx :  BaseException, std::exception {
  virtual const char* what() const noexcept { return "This won't be returned"; }
};

throw MyEx();

We are using Emscripten with the following switches: -s DISABLE_EXCEPTION_CATCHING=1 -fno-rtti. This means that we don't have a bound __get_exception_message, but we still have exceptions and we want to retrieve the reason using .what(). We thought that this code snippet would be sufficient for handling .what(), but it turns out it's not. Therefore, this part of the documentation is misleading.

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