xref: /aosp_15_r20/external/pytorch/c10/util/Exception.cpp (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Exception.h>
2*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Logging.h>
3*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Type.h>
4*da0073e9SAndroid Build Coastguard Worker 
5*da0073e9SAndroid Build Coastguard Worker #include <sstream>
6*da0073e9SAndroid Build Coastguard Worker #include <string>
7*da0073e9SAndroid Build Coastguard Worker #include <utility>
8*da0073e9SAndroid Build Coastguard Worker 
9*da0073e9SAndroid Build Coastguard Worker namespace c10 {
10*da0073e9SAndroid Build Coastguard Worker 
Error(std::string msg,Backtrace backtrace,const void * caller)11*da0073e9SAndroid Build Coastguard Worker Error::Error(std::string msg, Backtrace backtrace, const void* caller)
12*da0073e9SAndroid Build Coastguard Worker     : msg_(std::move(msg)), backtrace_(std::move(backtrace)), caller_(caller) {
13*da0073e9SAndroid Build Coastguard Worker   refresh_what();
14*da0073e9SAndroid Build Coastguard Worker }
15*da0073e9SAndroid Build Coastguard Worker 
16*da0073e9SAndroid Build Coastguard Worker // PyTorch-style error message
17*da0073e9SAndroid Build Coastguard Worker // Error::Error(SourceLocation source_location, const std::string& msg)
18*da0073e9SAndroid Build Coastguard Worker // NB: This is defined in Logging.cpp for access to GetFetchStackTrace
19*da0073e9SAndroid Build Coastguard Worker 
20*da0073e9SAndroid Build Coastguard Worker // Caffe2-style error message
Error(const char * file,const uint32_t line,const char * condition,const std::string & msg,Backtrace backtrace,const void * caller)21*da0073e9SAndroid Build Coastguard Worker Error::Error(
22*da0073e9SAndroid Build Coastguard Worker     const char* file,
23*da0073e9SAndroid Build Coastguard Worker     const uint32_t line,
24*da0073e9SAndroid Build Coastguard Worker     const char* condition,
25*da0073e9SAndroid Build Coastguard Worker     const std::string& msg,
26*da0073e9SAndroid Build Coastguard Worker     Backtrace backtrace,
27*da0073e9SAndroid Build Coastguard Worker     const void* caller)
28*da0073e9SAndroid Build Coastguard Worker     : Error(
29*da0073e9SAndroid Build Coastguard Worker           str("[enforce fail at ",
30*da0073e9SAndroid Build Coastguard Worker               detail::StripBasename(file),
31*da0073e9SAndroid Build Coastguard Worker               ":",
32*da0073e9SAndroid Build Coastguard Worker               line,
33*da0073e9SAndroid Build Coastguard Worker               "] ",
34*da0073e9SAndroid Build Coastguard Worker               condition,
35*da0073e9SAndroid Build Coastguard Worker               ". ",
36*da0073e9SAndroid Build Coastguard Worker               msg),
37*da0073e9SAndroid Build Coastguard Worker           std::move(backtrace),
38*da0073e9SAndroid Build Coastguard Worker           caller) {}
39*da0073e9SAndroid Build Coastguard Worker 
compute_what(bool include_backtrace) const40*da0073e9SAndroid Build Coastguard Worker std::string Error::compute_what(bool include_backtrace) const {
41*da0073e9SAndroid Build Coastguard Worker   std::ostringstream oss;
42*da0073e9SAndroid Build Coastguard Worker 
43*da0073e9SAndroid Build Coastguard Worker   oss << msg_;
44*da0073e9SAndroid Build Coastguard Worker 
45*da0073e9SAndroid Build Coastguard Worker   if (context_.size() == 1) {
46*da0073e9SAndroid Build Coastguard Worker     // Fold error and context in one line
47*da0073e9SAndroid Build Coastguard Worker     oss << " (" << context_[0] << ")";
48*da0073e9SAndroid Build Coastguard Worker   } else {
49*da0073e9SAndroid Build Coastguard Worker     for (const auto& c : context_) {
50*da0073e9SAndroid Build Coastguard Worker       oss << "\n  " << c;
51*da0073e9SAndroid Build Coastguard Worker     }
52*da0073e9SAndroid Build Coastguard Worker   }
53*da0073e9SAndroid Build Coastguard Worker 
54*da0073e9SAndroid Build Coastguard Worker   if (include_backtrace && backtrace_) {
55*da0073e9SAndroid Build Coastguard Worker     oss << "\n" << backtrace_->get();
56*da0073e9SAndroid Build Coastguard Worker   }
57*da0073e9SAndroid Build Coastguard Worker 
58*da0073e9SAndroid Build Coastguard Worker   return oss.str();
59*da0073e9SAndroid Build Coastguard Worker }
60*da0073e9SAndroid Build Coastguard Worker 
backtrace() const61*da0073e9SAndroid Build Coastguard Worker const Backtrace& Error::backtrace() const {
62*da0073e9SAndroid Build Coastguard Worker   return backtrace_;
63*da0073e9SAndroid Build Coastguard Worker }
64*da0073e9SAndroid Build Coastguard Worker 
what() const65*da0073e9SAndroid Build Coastguard Worker const char* Error::what() const noexcept {
66*da0073e9SAndroid Build Coastguard Worker   return what_
67*da0073e9SAndroid Build Coastguard Worker       .ensure([this] {
68*da0073e9SAndroid Build Coastguard Worker         try {
69*da0073e9SAndroid Build Coastguard Worker           return compute_what(/*include_backtrace*/ true);
70*da0073e9SAndroid Build Coastguard Worker         } catch (...) {
71*da0073e9SAndroid Build Coastguard Worker           // what() is noexcept, we need to return something here.
72*da0073e9SAndroid Build Coastguard Worker           return std::string{"<Error computing Error::what()>"};
73*da0073e9SAndroid Build Coastguard Worker         }
74*da0073e9SAndroid Build Coastguard Worker       })
75*da0073e9SAndroid Build Coastguard Worker       .c_str();
76*da0073e9SAndroid Build Coastguard Worker }
77*da0073e9SAndroid Build Coastguard Worker 
refresh_what()78*da0073e9SAndroid Build Coastguard Worker void Error::refresh_what() {
79*da0073e9SAndroid Build Coastguard Worker   // Do not compute what_ eagerly, as it would trigger the computation of the
80*da0073e9SAndroid Build Coastguard Worker   // backtrace. Instead, invalidate it, it will be computed on first access.
81*da0073e9SAndroid Build Coastguard Worker   // refresh_what() is only called by non-const public methods which are not
82*da0073e9SAndroid Build Coastguard Worker   // supposed to be called concurrently with any other method, so it is safe to
83*da0073e9SAndroid Build Coastguard Worker   // invalidate here.
84*da0073e9SAndroid Build Coastguard Worker   what_.reset();
85*da0073e9SAndroid Build Coastguard Worker   what_without_backtrace_ = compute_what(/*include_backtrace*/ false);
86*da0073e9SAndroid Build Coastguard Worker }
87*da0073e9SAndroid Build Coastguard Worker 
add_context(std::string new_msg)88*da0073e9SAndroid Build Coastguard Worker void Error::add_context(std::string new_msg) {
89*da0073e9SAndroid Build Coastguard Worker   context_.push_back(std::move(new_msg));
90*da0073e9SAndroid Build Coastguard Worker   // TODO: Calling add_context O(n) times has O(n^2) cost.  We can fix
91*da0073e9SAndroid Build Coastguard Worker   // this perf problem by populating the fields lazily... if this ever
92*da0073e9SAndroid Build Coastguard Worker   // actually is a problem.
93*da0073e9SAndroid Build Coastguard Worker   // NB: If you do fix this, make sure you do it in a thread safe way!
94*da0073e9SAndroid Build Coastguard Worker   // what() is almost certainly expected to be thread safe even when
95*da0073e9SAndroid Build Coastguard Worker   // accessed across multiple threads
96*da0073e9SAndroid Build Coastguard Worker   refresh_what();
97*da0073e9SAndroid Build Coastguard Worker }
98*da0073e9SAndroid Build Coastguard Worker 
99*da0073e9SAndroid Build Coastguard Worker namespace detail {
100*da0073e9SAndroid Build Coastguard Worker 
torchCheckFail(const char * func,const char * file,uint32_t line,const std::string & msg)101*da0073e9SAndroid Build Coastguard Worker void torchCheckFail(
102*da0073e9SAndroid Build Coastguard Worker     const char* func,
103*da0073e9SAndroid Build Coastguard Worker     const char* file,
104*da0073e9SAndroid Build Coastguard Worker     uint32_t line,
105*da0073e9SAndroid Build Coastguard Worker     const std::string& msg) {
106*da0073e9SAndroid Build Coastguard Worker   throw ::c10::Error({func, file, line}, msg);
107*da0073e9SAndroid Build Coastguard Worker }
108*da0073e9SAndroid Build Coastguard Worker 
torchCheckFail(const char * func,const char * file,uint32_t line,const char * msg)109*da0073e9SAndroid Build Coastguard Worker void torchCheckFail(
110*da0073e9SAndroid Build Coastguard Worker     const char* func,
111*da0073e9SAndroid Build Coastguard Worker     const char* file,
112*da0073e9SAndroid Build Coastguard Worker     uint32_t line,
113*da0073e9SAndroid Build Coastguard Worker     const char* msg) {
114*da0073e9SAndroid Build Coastguard Worker   throw ::c10::Error({func, file, line}, msg);
115*da0073e9SAndroid Build Coastguard Worker }
116*da0073e9SAndroid Build Coastguard Worker 
torchInternalAssertFail(const char * func,const char * file,uint32_t line,const char * condMsg,const char * userMsg)117*da0073e9SAndroid Build Coastguard Worker void torchInternalAssertFail(
118*da0073e9SAndroid Build Coastguard Worker     const char* func,
119*da0073e9SAndroid Build Coastguard Worker     const char* file,
120*da0073e9SAndroid Build Coastguard Worker     uint32_t line,
121*da0073e9SAndroid Build Coastguard Worker     const char* condMsg,
122*da0073e9SAndroid Build Coastguard Worker     const char* userMsg) {
123*da0073e9SAndroid Build Coastguard Worker   torchCheckFail(func, file, line, c10::str(condMsg, userMsg));
124*da0073e9SAndroid Build Coastguard Worker }
125*da0073e9SAndroid Build Coastguard Worker 
126*da0073e9SAndroid Build Coastguard Worker // This should never be called. It is provided in case of compilers
127*da0073e9SAndroid Build Coastguard Worker // that don't do any dead code stripping in debug builds.
torchInternalAssertFail(const char * func,const char * file,uint32_t line,const char * condMsg,const std::string & userMsg)128*da0073e9SAndroid Build Coastguard Worker void torchInternalAssertFail(
129*da0073e9SAndroid Build Coastguard Worker     const char* func,
130*da0073e9SAndroid Build Coastguard Worker     const char* file,
131*da0073e9SAndroid Build Coastguard Worker     uint32_t line,
132*da0073e9SAndroid Build Coastguard Worker     const char* condMsg,
133*da0073e9SAndroid Build Coastguard Worker     const std::string& userMsg) {
134*da0073e9SAndroid Build Coastguard Worker   torchCheckFail(func, file, line, c10::str(condMsg, userMsg));
135*da0073e9SAndroid Build Coastguard Worker }
136*da0073e9SAndroid Build Coastguard Worker 
137*da0073e9SAndroid Build Coastguard Worker } // namespace detail
138*da0073e9SAndroid Build Coastguard Worker 
139*da0073e9SAndroid Build Coastguard Worker namespace WarningUtils {
140*da0073e9SAndroid Build Coastguard Worker 
141*da0073e9SAndroid Build Coastguard Worker namespace {
getBaseHandler()142*da0073e9SAndroid Build Coastguard Worker WarningHandler* getBaseHandler() {
143*da0073e9SAndroid Build Coastguard Worker   static WarningHandler base_warning_handler_ = WarningHandler();
144*da0073e9SAndroid Build Coastguard Worker   return &base_warning_handler_;
145*da0073e9SAndroid Build Coastguard Worker }
146*da0073e9SAndroid Build Coastguard Worker 
147*da0073e9SAndroid Build Coastguard Worker class ThreadWarningHandler {
148*da0073e9SAndroid Build Coastguard Worker  public:
149*da0073e9SAndroid Build Coastguard Worker   ThreadWarningHandler() = delete;
150*da0073e9SAndroid Build Coastguard Worker 
get_handler()151*da0073e9SAndroid Build Coastguard Worker   static WarningHandler* get_handler() {
152*da0073e9SAndroid Build Coastguard Worker     if (!warning_handler_) {
153*da0073e9SAndroid Build Coastguard Worker       warning_handler_ = getBaseHandler();
154*da0073e9SAndroid Build Coastguard Worker     }
155*da0073e9SAndroid Build Coastguard Worker     return warning_handler_;
156*da0073e9SAndroid Build Coastguard Worker   }
157*da0073e9SAndroid Build Coastguard Worker 
set_handler(WarningHandler * handler)158*da0073e9SAndroid Build Coastguard Worker   static void set_handler(WarningHandler* handler) {
159*da0073e9SAndroid Build Coastguard Worker     warning_handler_ = handler;
160*da0073e9SAndroid Build Coastguard Worker   }
161*da0073e9SAndroid Build Coastguard Worker 
162*da0073e9SAndroid Build Coastguard Worker  private:
163*da0073e9SAndroid Build Coastguard Worker   static thread_local WarningHandler* warning_handler_;
164*da0073e9SAndroid Build Coastguard Worker };
165*da0073e9SAndroid Build Coastguard Worker 
166*da0073e9SAndroid Build Coastguard Worker thread_local WarningHandler* ThreadWarningHandler::warning_handler_ = nullptr;
167*da0073e9SAndroid Build Coastguard Worker 
168*da0073e9SAndroid Build Coastguard Worker } // namespace
169*da0073e9SAndroid Build Coastguard Worker 
set_warning_handler(WarningHandler * handler)170*da0073e9SAndroid Build Coastguard Worker void set_warning_handler(WarningHandler* handler) noexcept(true) {
171*da0073e9SAndroid Build Coastguard Worker   ThreadWarningHandler::set_handler(handler);
172*da0073e9SAndroid Build Coastguard Worker }
173*da0073e9SAndroid Build Coastguard Worker 
get_warning_handler()174*da0073e9SAndroid Build Coastguard Worker WarningHandler* get_warning_handler() noexcept(true) {
175*da0073e9SAndroid Build Coastguard Worker   return ThreadWarningHandler::get_handler();
176*da0073e9SAndroid Build Coastguard Worker }
177*da0073e9SAndroid Build Coastguard Worker 
178*da0073e9SAndroid Build Coastguard Worker bool warn_always = false;
179*da0073e9SAndroid Build Coastguard Worker 
set_warnAlways(bool setting)180*da0073e9SAndroid Build Coastguard Worker void set_warnAlways(bool setting) noexcept(true) {
181*da0073e9SAndroid Build Coastguard Worker   warn_always = setting;
182*da0073e9SAndroid Build Coastguard Worker }
183*da0073e9SAndroid Build Coastguard Worker 
get_warnAlways()184*da0073e9SAndroid Build Coastguard Worker bool get_warnAlways() noexcept(true) {
185*da0073e9SAndroid Build Coastguard Worker   return warn_always;
186*da0073e9SAndroid Build Coastguard Worker }
187*da0073e9SAndroid Build Coastguard Worker 
WarnAlways(bool setting)188*da0073e9SAndroid Build Coastguard Worker WarnAlways::WarnAlways(bool setting /*=true*/)
189*da0073e9SAndroid Build Coastguard Worker     : prev_setting(get_warnAlways()) {
190*da0073e9SAndroid Build Coastguard Worker   set_warnAlways(setting);
191*da0073e9SAndroid Build Coastguard Worker }
192*da0073e9SAndroid Build Coastguard Worker 
~WarnAlways()193*da0073e9SAndroid Build Coastguard Worker WarnAlways::~WarnAlways() {
194*da0073e9SAndroid Build Coastguard Worker   set_warnAlways(prev_setting);
195*da0073e9SAndroid Build Coastguard Worker }
196*da0073e9SAndroid Build Coastguard Worker 
197*da0073e9SAndroid Build Coastguard Worker } // namespace WarningUtils
198*da0073e9SAndroid Build Coastguard Worker 
warn(const Warning & warning)199*da0073e9SAndroid Build Coastguard Worker void warn(const Warning& warning) {
200*da0073e9SAndroid Build Coastguard Worker   WarningUtils::ThreadWarningHandler::get_handler()->process(warning);
201*da0073e9SAndroid Build Coastguard Worker }
202*da0073e9SAndroid Build Coastguard Worker 
Warning(warning_variant_t type,const SourceLocation & source_location,std::string msg,const bool verbatim)203*da0073e9SAndroid Build Coastguard Worker Warning::Warning(
204*da0073e9SAndroid Build Coastguard Worker     warning_variant_t type,
205*da0073e9SAndroid Build Coastguard Worker     const SourceLocation& source_location,
206*da0073e9SAndroid Build Coastguard Worker     std::string msg,
207*da0073e9SAndroid Build Coastguard Worker     const bool verbatim)
208*da0073e9SAndroid Build Coastguard Worker     : type_(type),
209*da0073e9SAndroid Build Coastguard Worker       source_location_(source_location),
210*da0073e9SAndroid Build Coastguard Worker       msg_(std::move(msg)),
211*da0073e9SAndroid Build Coastguard Worker       verbatim_(verbatim) {}
212*da0073e9SAndroid Build Coastguard Worker 
Warning(warning_variant_t type,SourceLocation source_location,detail::CompileTimeEmptyString msg,const bool verbatim)213*da0073e9SAndroid Build Coastguard Worker Warning::Warning(
214*da0073e9SAndroid Build Coastguard Worker     warning_variant_t type,
215*da0073e9SAndroid Build Coastguard Worker     SourceLocation source_location,
216*da0073e9SAndroid Build Coastguard Worker     detail::CompileTimeEmptyString msg,
217*da0073e9SAndroid Build Coastguard Worker     const bool verbatim)
218*da0073e9SAndroid Build Coastguard Worker     : Warning(type, source_location, "", verbatim) {}
219*da0073e9SAndroid Build Coastguard Worker 
Warning(warning_variant_t type,SourceLocation source_location,const char * msg,const bool verbatim)220*da0073e9SAndroid Build Coastguard Worker Warning::Warning(
221*da0073e9SAndroid Build Coastguard Worker     warning_variant_t type,
222*da0073e9SAndroid Build Coastguard Worker     SourceLocation source_location,
223*da0073e9SAndroid Build Coastguard Worker     const char* msg,
224*da0073e9SAndroid Build Coastguard Worker     const bool verbatim)
225*da0073e9SAndroid Build Coastguard Worker     : type_(type),
226*da0073e9SAndroid Build Coastguard Worker       source_location_(source_location),
227*da0073e9SAndroid Build Coastguard Worker       msg_(std::string(msg)),
228*da0073e9SAndroid Build Coastguard Worker       verbatim_(verbatim) {}
229*da0073e9SAndroid Build Coastguard Worker 
type() const230*da0073e9SAndroid Build Coastguard Worker Warning::warning_variant_t Warning::type() const {
231*da0073e9SAndroid Build Coastguard Worker   return type_;
232*da0073e9SAndroid Build Coastguard Worker }
233*da0073e9SAndroid Build Coastguard Worker 
source_location() const234*da0073e9SAndroid Build Coastguard Worker const SourceLocation& Warning::source_location() const {
235*da0073e9SAndroid Build Coastguard Worker   return source_location_;
236*da0073e9SAndroid Build Coastguard Worker }
237*da0073e9SAndroid Build Coastguard Worker 
msg() const238*da0073e9SAndroid Build Coastguard Worker const std::string& Warning::msg() const {
239*da0073e9SAndroid Build Coastguard Worker   return msg_;
240*da0073e9SAndroid Build Coastguard Worker }
241*da0073e9SAndroid Build Coastguard Worker 
verbatim() const242*da0073e9SAndroid Build Coastguard Worker bool Warning::verbatim() const {
243*da0073e9SAndroid Build Coastguard Worker   return verbatim_;
244*da0073e9SAndroid Build Coastguard Worker }
245*da0073e9SAndroid Build Coastguard Worker 
process(const Warning & warning)246*da0073e9SAndroid Build Coastguard Worker void WarningHandler::process(const Warning& warning) {
247*da0073e9SAndroid Build Coastguard Worker   LOG_AT_FILE_LINE(
248*da0073e9SAndroid Build Coastguard Worker       WARNING, warning.source_location().file, warning.source_location().line)
249*da0073e9SAndroid Build Coastguard Worker       << "Warning: " << warning.msg() << " (function "
250*da0073e9SAndroid Build Coastguard Worker       << warning.source_location().function << ")";
251*da0073e9SAndroid Build Coastguard Worker }
252*da0073e9SAndroid Build Coastguard Worker 
GetExceptionString(const std::exception & e)253*da0073e9SAndroid Build Coastguard Worker std::string GetExceptionString(const std::exception& e) {
254*da0073e9SAndroid Build Coastguard Worker #ifdef __GXX_RTTI
255*da0073e9SAndroid Build Coastguard Worker   return demangle(typeid(e).name()) + ": " + e.what();
256*da0073e9SAndroid Build Coastguard Worker #else
257*da0073e9SAndroid Build Coastguard Worker   return std::string("Exception (no RTTI available): ") + e.what();
258*da0073e9SAndroid Build Coastguard Worker #endif // __GXX_RTTI
259*da0073e9SAndroid Build Coastguard Worker }
260*da0073e9SAndroid Build Coastguard Worker 
261*da0073e9SAndroid Build Coastguard Worker } // namespace c10
262