|
Rcpp Version 0.9.10
|
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- 00002 // 00003 // exceptions.cpp: R/C++ interface class library -- exception handling 00004 // 00005 // Copyright (C) 2009 - 2011 Dirk Eddelbuettel and Romain Francois 00006 // 00007 // This file is part of Rcpp. 00008 // 00009 // Rcpp is free software: you can redistribute it and/or modify it 00010 // under the terms of the GNU General Public License as published by 00011 // the Free Software Foundation, either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // Rcpp is distributed in the hope that it will be useful, but 00015 // WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 // GNU General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU General Public License 00020 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>. 00021 00022 #include <Rcpp.h> 00023 00024 namespace Rcpp{ 00025 exception::exception( const char* message_, const char* file, int line) : message(message_){ 00026 rcpp_set_stack_trace( stack_trace(file,line) ) ; 00027 } 00028 exception::~exception() throw(){} 00029 00030 #define RCPP_EXCEPTION_WHAT(__CLASS__) \ 00031 const char* __CLASS__::what() const throw(){ return message.c_str(); } 00032 00033 RCPP_EXCEPTION_WHAT(exception) 00034 00035 RCPP_EXCEPTION_WHAT(not_compatible) 00036 RCPP_EXCEPTION_WHAT(S4_creation_error) 00037 RCPP_EXCEPTION_WHAT(reference_creation_error) 00038 RCPP_EXCEPTION_WHAT(no_such_binding) 00039 RCPP_EXCEPTION_WHAT(binding_not_found) 00040 RCPP_EXCEPTION_WHAT(binding_is_locked) 00041 RCPP_EXCEPTION_WHAT(no_such_namespace) 00042 RCPP_EXCEPTION_WHAT(eval_error) 00043 00044 #undef RCPP_EXCEPTION_WHAT 00045 00046 #define RCPP_SIMPLE_EXCEPTION_WHAT(__CLASS__,__MESSAGE__) \ 00047 const char* __CLASS__::what() const throw(){ return __MESSAGE__ ; } 00048 00049 RCPP_SIMPLE_EXCEPTION_WHAT(not_a_matrix, "not a matrix" ) 00050 RCPP_SIMPLE_EXCEPTION_WHAT(index_out_of_bounds, "index out of bounds" ) 00051 RCPP_SIMPLE_EXCEPTION_WHAT(parse_error, "parse error") 00052 RCPP_SIMPLE_EXCEPTION_WHAT(not_s4, "not an S4 object" ) 00053 RCPP_SIMPLE_EXCEPTION_WHAT(not_reference, "not a reference S4 object" ) 00054 RCPP_SIMPLE_EXCEPTION_WHAT(not_initialized, "C++ object not initialized" ) 00055 RCPP_SIMPLE_EXCEPTION_WHAT(no_such_slot, "no such slot" ) 00056 RCPP_SIMPLE_EXCEPTION_WHAT(no_such_field, "no such field" ) 00057 RCPP_SIMPLE_EXCEPTION_WHAT(not_a_closure, "not a closure" ) 00058 RCPP_SIMPLE_EXCEPTION_WHAT(no_such_function, "no such function" ) 00059 RCPP_SIMPLE_EXCEPTION_WHAT(unevaluated_promise, "promise not yet evaluated" ) 00060 00061 #undef RCPP_SIMPLE_EXCEPTION_WHAT 00062 } 00063 00064 /* for now, the fancy exception handling is only available in GCC, 00065 simply because we've not investigated if it is available in other 00066 compilers */ 00067 #ifdef RCPP_HAS_DEMANGLING 00068 #include <typeinfo> 00069 #ifdef IS_EARLIER_THAN_GCC_460 00070 #include <exception_defines.h> 00071 #endif 00072 #include <cxxabi.h> 00073 00074 std::string demangle( const std::string& name ){ 00075 std::string real_class ; 00076 int status =-1 ; 00077 char *dem = 0; 00078 dem = abi::__cxa_demangle(name.c_str(), 0, 0, &status); 00079 if( status == 0 ){ 00080 real_class = dem ; 00081 free(dem); 00082 } else { 00083 real_class = name ; 00084 } 00085 return real_class ; 00086 } 00087 00088 /* much inspired from the __verbose_terminate_handler of the GCC */ 00089 void forward_uncaught_exceptions_to_r(){ 00090 00091 std::string exception_class ; 00092 bool has_exception_class = false; 00093 std::string exception_what ; 00094 00095 // Make sure there was an exception; terminate is also called for an 00096 // attempt to rethrow when there is no suitable exception. 00097 std::type_info *t = abi::__cxa_current_exception_type(); 00098 if (t){ 00099 has_exception_class = true ; 00100 const char *name = t->name() ; 00101 // now we need to demangle "name" 00102 00103 { 00104 int status = -1; 00105 char *dem = 0; 00106 dem = abi::__cxa_demangle(name, 0, 0, &status); 00107 if( status == 0){ 00108 exception_class = dem ; /* great we can use the demangled name */ 00109 free(dem); 00110 } else{ 00111 exception_class = name ; /* just using the mangled name */ 00112 } 00113 } 00114 } 00115 00116 // If the exception is derived from std::exception, we can give more 00117 // information. 00118 try { 00119 __throw_exception_again; 00120 } catch (std::exception &exc) { 00121 exception_what = exc.what() ; 00122 } catch (...) { 00123 exception_what = "unrecognized exception" ; 00124 } 00125 00126 SEXP cppExceptSym = Rf_install("cpp_exception"); // cannot cause a gc() once in symbol table 00127 Rf_eval( 00128 Rf_lang3( 00129 cppExceptSym, 00130 Rf_mkString(exception_what.c_str()), 00131 has_exception_class ? Rf_mkString(exception_class.c_str()) : R_NilValue), 00132 R_FindNamespace(Rf_mkString("Rcpp")) 00133 ) ; 00134 } 00135 void forward_exception_to_r( const std::exception& ex){ 00136 std::string exception_class ; 00137 std::string exception_what = ex.what(); 00138 const char *name = typeid(ex).name() ; 00139 // now we need to demangle "name" 00140 { 00141 int status = -1; 00142 char *dem = 0; 00143 dem = abi::__cxa_demangle(name, 0, 0, &status); 00144 if( status == 0){ 00145 exception_class = dem ; /* great we can use the demangled name */ 00146 free(dem); 00147 } else{ 00148 exception_class = name ; /* just using the mangled name */ 00149 } 00150 } 00151 SEXP cppExceptSym = Rf_install("cpp_exception"); // cannot cause a gc() once in symbol table 00152 Rf_eval( 00153 Rf_lang3( 00154 cppExceptSym, 00155 Rf_mkString(exception_what.c_str()), 00156 Rf_mkString(exception_class.c_str()) 00157 ), R_FindNamespace(Rf_mkString("Rcpp")) 00158 ) ; 00159 } 00160 #else 00161 void forward_uncaught_exceptions_to_r(){ 00162 SEXP cppExceptSym = Rf_install("cpp_exception"); // cannot cause a gc() once in symbol table 00163 Rf_eval( 00164 Rf_lang3( 00165 cppExceptSym, 00166 Rf_mkString("exception : we don't know how to get the exception message with your compiler, patches welcome"), 00167 R_NilValue), 00168 R_FindNamespace(Rf_mkString("Rcpp")) 00169 ) ; 00170 } 00171 void forward_exception_to_r( const std::exception& ex){ 00172 SEXP cppExceptSym = Rf_install("cpp_exception"); // cannot cause a gc() once in symbol table 00173 Rf_eval( 00174 Rf_lang3( 00175 cppExceptSym, 00176 Rf_mkString(ex.what()), 00177 R_NilValue), 00178 R_FindNamespace(Rf_mkString("Rcpp")) 00179 ) ; 00180 00181 } 00182 std::string demangle( const std::string& name ){ 00183 return name ; 00184 } 00185 #endif 00186 SEXP initUncaughtExceptionHandler(){ 00187 /* FIXME: we might want to restore the original handler as the package 00188 gets unloaded */ 00189 std::set_terminate(forward_uncaught_exceptions_to_r); 00190 return R_NilValue ; 00191 } 00192