onnxruntime: Provide a way to handle errors in the C++ API when exceptions are disabled

I’m using ONNX Runtime as a shared library inside a project where exceptions are disabled and enabling them is not an option. So, to avoid build errors from the throw statements I define the macro ORT_NO_EXCEPTIONS. However, doing so causes std::abort() to be called on error.

Now let’s say that, as part of some other bigger process, I want to create an Ort::Session to check if a model file is fine and extract its metadata. If things go wrong, I just want to say “nope, this didn’t work” and carry on. However, because exceptions are disabled, the current API provides no way to handle the error if there is a problem. The entire process just dies from the call to std::abort().

Would it be possible to provide a way to handle errors in the C++ API when exceptions are disabled?

System information

  • ONNX Runtime version (you are using): v1.10.0

Describe the solution you’d like I’d like to have some way to get an OrtStatus I can use to handle errors instead of an automatic std::abort() when exceptions are disabled. Ideally this would apply to any C++ APIs that currently have this throw on error behavior, but at the very least I’d like it when initializing Ort::Session objects and running them.

Describe alternatives you’ve considered I’ve tried using the underlying APIs that Ort::Session constructors call to handle the error, but the p_ pointer is declared as protected and cannot be accessed externally. This forces me out of the Ort::Session API.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 15 (15 by maintainers)

Commits related to this issue

Most upvoted comments

@RyanUnderhill Sorry to reopen this, but the way the patch is implemented is in fact preventing me from defining my own ORT_CXX_API_THROW.

The issue is that I also define ORT_NO_EXCEPTIONS (which is the very reason I need to customize error management, because I cannot use exceptions), but as it is now you can only redefine ORT_CXX_API_THROW when ORT_NO_EXCEPTIONS is not defined.

This is how it looks like now.

#ifdef ORT_NO_EXCEPTIONS
#define ORT_CXX_API_THROW(string, code)       \
  do {                                        \
    std::cerr << Ort::Exception(string, code) \
                     .what()                  \
              << std::endl;                   \
    abort();                                  \
  } while (false)
#else
// The #ifndef is for the very special case where the user of this library wants to define their own way of handling errors.
// NOTE: This header expects control flow to not continue after calling ORT_CXX_API_THROW
#ifndef ORT_CXX_API_THROW
#define ORT_CXX_API_THROW(string, code) \
  throw Ort::Exception(string, code)
#endif
#endif

Instead, it should be something like this:

#ifdef ORT_NO_EXCEPTIONS
// The #ifndef is for the very special case where the user of this library wants to define their own way of handling errors.
// NOTE: This header expects control flow to not continue after calling ORT_CXX_API_THROW
#ifndef ORT_CXX_API_THROW
#define ORT_CXX_API_THROW(string, code)       \
  do {                                        \
    std::cerr << Ort::Exception(string, code) \
                     .what()                  \
              << std::endl;                   \
    abort();                                  \
  } while (false)
#endif
#else
#define ORT_CXX_API_THROW(string, code) \
  throw Ort::Exception(string, code)
#endif

Or alternatively, allow redefinition in both cases if you think that’s more appropriate. My use case only needs to allow redefinition when ORT_NO_EXCEPTIONS is defined.