#ifndef C10_UTIL_EXCEPTION_H_
#define C10_UTIL_EXCEPTION_H_
#include <c10/macros/Macros.h>
#include <c10/util/StringUtil.h>
#include <c10/util/Deprecated.h>
#include <cstddef>
#include <exception>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
#if defined(_MSC_VER) && _MSC_VER <= 1900
#define __func__ __FUNCTION__
#endif
namespace c10 {
/// The primary ATen error class.
/// Provides a complete error message with source location information via
/// `what()`, and a more concise message via `what_without_backtrace()`.
/// Don't throw this directly; use TORCH_CHECK/TORCH_INTERNAL_ASSERT instead.
///
/// NB: c10::Error is handled specially by the default torch to suppress the
/// backtrace, see torch/csrc/Exceptions.h
class C10_API Error : public std::exception {
// The actual error message.
std::string msg_;
// Context for the message (in order of decreasing specificity). Context will
// be automatically formatted appropriately, so it is not necessary to add
// extra leading/trailing newlines to strings inside this vector
std::vector<std::string> context_;
// The C++ backtrace at the point when this exception was raised. This
// may be empty if there is no valid backtrace. (We don't use optional
// here to reduce the dependencies this file has.)
std::string backtrace_;
// These two are derived fields from msg_stack_ and backtrace_, but we need
// fields for the strings so that we can return a const char* (as the
// signature of std::exception requires). Currently, the invariant
// is that these fields are ALWAYS populated consistently with respect
// to msg_stack_ and backtrace_.
std::string what_;
std::string what_without_backtrace_;
// This is a little debugging trick: you can stash a relevant pointer
// in caller, and then when you catch the exception, you can compare
// against pointers you have on hand to get more information about
// where the exception came from. In Caffe2, this is used to figure
// out which operator raised an exception.
const void* caller_;
public:
// PyTorch-style Error constructor. NB: the implementation of this
// is actually in Logging.cpp
Error(SourceLocation source_location, std::string msg);
// Caffe2-style error message
Error(
const char* file,
const uint32_t line,
const char* condition,
const std::string& msg,
const std::string& backtrace,
const void* caller = nullptr);
// Base constructor
Error(
std::string msg,
std::string backtrace,
const void* caller = nullptr);
// Add some new context to the message stack. The last added context
// will be formatted at the end of the context list upon printing.
// WARNING: This method is O(n) in the size of the stack, so don't go
// wild adding a ridiculous amount of context to error messages.
void add_context(std::string msg);
const std::string& msg() const {
return msg_;
}
const std::vector<std::string>& context() const {
return context_;
}
const std::string& backtrace() const {
return backtrace_;
}
/// Returns the complete error message, including the source location.
/// The returned pointer is invalidated if you call add_context() on
/// this object.
const char* what() const noexcept override {
return what_.c_str();
}
const void* caller() const noexcept {
return caller_;
}
/// Returns only the error message string, without source location.
/// The returned pointer is invalidated if you call add_context() on
/// this object.
const char* what_without_backtrace() const noexcept {
return what_without_backtrace_.c_str();
}
private:
void refresh_what();
std::string compute_what(bool include_backtrace) const;
};
class C10_API WarningHandler {
public:
virtual ~WarningHandler() noexcept(false) {}
/// The default warning handler. Prints the message to stderr.
virtual void process(
const SourceLocation& source_location,
const std::string& msg,
const bool verbatim);
};
namespace Warning {
// Note: [Verbatim Warnings]
// Warnings originating in C++ code can appear out-of-place to Python users:
// a user runs a line in Python, but the warning references a line in C++.
// Some parts of PyTorch, like the JIT, are cognizant of this mismatch
// and take care to map warnings back to the user's program, but most
// of PyTorch simply throws a context-free warning. To allow warning
// handlers to add context where appropriate, warn takes the
// "verbatim" flag. When this is false a warning handler might append
// the C++ warning to a Python warning message that relates the warning
// back to the user's program. Callers who have already accounted for
// context in their warnings should set verbatim to true so their warnings
// appear without modification.
/// Issue a warning with a given message. Dispatched to the current
/// warning handler.
C10_API void warn(SourceLocation source_location,
const std::string& msg,
bool verbatim);
/// Sets the global warning handler. This is not thread-safe, so it should
/// generally be called once during initialization or while holding the GIL
/// for programs that use python.
/// User is responsible for keeping the WarningHandler alive until
/// it is not needed.
C10_API void set_warning_handler(WarningHandler* handler) noexcept(true);
/// Gets the global warning handler.
C10_API WarningHandler* get_warning_handler() noexcept(true);
} // namespace Warning
// Used in ATen for out-of-bound indices that can reasonably only be detected
// lazily inside a kernel (See: advanced indexing). These turn into
// IndexError when they cross to Python.
class C10_API IndexError : public Error {
using Error::Error;
};
// Used in ATen for invalid values. These turn into
// ValueError when they cross to Python.
class C10_API ValueError : public Error {
using Error::Error;
};
// Used in ATen for invalid types. These turn into
// TypeError when they cross to Python.
class C10_API TypeError : public Error {
using Error::Error;
};
// Used in ATen for non finite indices. These turn into
// ExitException when they cross to Python.
class C10_API EnforceFiniteError : public Error {
using Error::Error;
};
// Used in Onnxifi backend lowering. These turn into
// ExitException when they cross to Python.
class C10_API OnnxfiBackendSystemError : public Error {
using Error::Error;
};
// A utility function to return an exception std::string by prepending its
// exception type before its what() content
C10_API std::string GetExceptionString(const std::exception& e);
namespace detail {
// Return x if it is non-empty; otherwise return y.
inline std::string if_empty_then(const std::string& x, const std::string& y) {
if (x.empty()) {
return y;
} else {
return x;
}
}
}
} // namespace c10
// Private helper macro for implementing TORCH_INTERNAL_ASSERT and TORCH_CHECK
//
// Note: In the debug build With MSVC, __LINE__ might be of long type (a.k.a int32_t),
// which is different from the definition of `SourceLocation` that requires
// unsigned int (a.k.a uint32_t) and may cause a compile error with the message:
// error C2397: conversion from 'long' to 'uint32_t' requires a narrowing conversion
// Here the static cast is used to pass the build.
// if this is used inside a lambda the __func__ macro expands to operator(),
// which isn't very useful, but hard to fix in a macro so suppressing the warning.
#define C10_THROW_ERROR(err_type, msg) \
throw ::c10::err_type({__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, msg)
// Private helper macro for workaround MSVC misexpansion of nested macro
// invocations involving __VA_ARGS__. See
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
#define C10_EXPAND_MSVC_WORKAROUND(x) x
// On nvcc, C10_UNLIKELY thwarts missing return statement analysis. In cases
// where the unlikely expression may be a constant, use this macro to ensure
// return statement analysis keeps working (at the cost of not getting the
// likely/unlikely annotation on nvcc). https://github.com/pytorch/pytorch/issues/21418
//
// Currently, this is only used in the error reporting macros below. If you
// want to use it more generally, move me to Macros.h
//
// TODO: Brian Vaughan observed that we might be able to get this to work on nvcc
// by writing some sort of C++ overload that distinguishes constexpr inputs
// from non-constexpr. Since there isn't any evidence that losing C10_UNLIKELY
// in nvcc is causing us perf problems, this is not yet implemented, but this
// might be an interesting piece of C++ code for an intrepid bootcamper to
// write.
#if defined(__CUDACC__)
#define C10_UNLIKELY_OR_CONST(e) e
#else
#define C10_UNLIKELY_OR_CONST(e) C10_UNLIKELY(e)
#endif
// ----------------------------------------------------------------------------
// Error reporting macros
// ----------------------------------------------------------------------------
#ifdef STRIP_ERROR_MESSAGES
#define TORCH_RETHROW(e, ...) throw
#else
#define TORCH_RETHROW(e, ...) \
do { \
e.add_context(::c10::str(__VA_ARGS__)); \
throw; \
} while (false)
#endif
// A utility macro to provide assert()-like functionality; that is, enforcement
// of internal invariants in code. It supports an arbitrary number of extra
// arguments (evaluated only on failure), which will be printed in the assert
// failure message using operator<< (this is useful to print some variables
// which may be useful for debugging.)
//
// Usage:
// TORCH_INTERNAL_ASSERT(should_be_true);
// TORCH_INTERNAL_ASSERT(x == 0, "x = ", x);
//
// Assuming no bugs in PyTorch, the conditions tested by this macro should
// always be true; e.g., it should be possible to disable all of these
// conditions without changing observable user behavior. If you would like to
// do error reporting for user input, please use TORCH_CHECK instead.
//
// NOTE: It is SAFE to use this macro in production code; on failure, this
// simply raises an exception, it does NOT unceremoniously quit the process
// (unlike assert()).
//
#ifdef STRIP_ERROR_MESSAGES
#define TORCH_INTERNAL_ASSERT(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, \
#cond " INTERNAL ASSERT FAILED at" \
C10_STRINGIZE(__FILE__) \
); \
}
#else
#define TORCH_INTERNAL_ASSERT(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, ::c10::str( \
#cond " INTERNAL ASSERT FAILED at " \
C10_STRINGIZE(__FILE__) \
":" \
C10_STRINGIZE(__LINE__) \
", please report a bug to PyTorch. ", \
::c10::str(__VA_ARGS__) \
)); \
}
#endif
// A utility macro to make it easier to test for error conditions from user
// input. Like TORCH_INTERNAL_ASSERT, it supports an arbitrary number of extra
// arguments (evaluated only on failure), which will be printed in the error
// message using operator<< (e.g., you can pass any object which has
// operator<< defined. Most objects in PyTorch have these definitions!)
//
// Usage:
// TORCH_CHECK(should_be_true); // A default error message will be provided
// // in this case; but we recommend writing an
// // explicit error message, as it is more
// // user friendly.
// TORCH_CHECK(x == 0, "Expected x to be 0, but got ", x);
//
// On failure, this macro will raise an exception. If this exception propagates
// to Python, it will convert into a Python RuntimeError.
//
// NOTE: It is SAFE to use this macro in production code; on failure, this
// simply raises an exception, it does NOT unceremoniously quit the process
// (unlike CHECK() from glog.)
//
#define TORCH_CHECK_WITH(error_t, cond, ...) \
TORCH_CHECK_WITH_MSG(error_t, cond, "", __VA_ARGS__)
#ifdef STRIP_ERROR_MESSAGES
#define TORCH_CHECK_MSG(cond, type, ...) \
(#cond #type " CHECK FAILED at " \
C10_STRINGIZE(__FILE__))
#define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, \
TORCH_CHECK_MSG(cond, type, __VA_ARGS__) \
); \
}
#else
#define TORCH_CHECK_MSG(cond, type, ...) \
::c10::detail::if_empty_then( \
::c10::str(__VA_ARGS__), \
"Expected " #cond " to be true, but got false. " \
"(Could this error message be improved? If so, " \
"please report an enhancement request to PyTorch.)" \
)
#define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
Loading ...