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