v8js_exceptions.cc 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | http://www.opensource.org/licenses/mit-license.php MIT License |
  8. +----------------------------------------------------------------------+
  9. | Author: Jani Taskinen <[email protected]> |
  10. | Author: Patrick Reilly <[email protected]> |
  11. | Author: Stefan Siegl <[email protected]> |
  12. +----------------------------------------------------------------------+
  13. */
  14. #ifdef HAVE_CONFIG_H
  15. #include "config.h"
  16. #endif
  17. #include "php_v8js_macros.h"
  18. extern "C" {
  19. #include "ext/date/php_date.h"
  20. #include "ext/standard/php_string.h"
  21. #include "zend_interfaces.h"
  22. #include "zend_closures.h"
  23. #include "ext/spl/spl_exceptions.h"
  24. #include "zend_exceptions.h"
  25. }
  26. /* {{{ Class Entries */
  27. zend_class_entry *php_ce_v8js_exception;
  28. zend_class_entry *php_ce_v8js_script_exception;
  29. zend_class_entry *php_ce_v8js_time_limit_exception;
  30. zend_class_entry *php_ce_v8js_memory_limit_exception;
  31. /* }}} */
  32. /* {{{ Class: V8JsScriptException */
  33. void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8::TryCatch *try_catch) /* {{{ */
  34. {
  35. v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0);
  36. v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, ctx->context);
  37. v8::String::Utf8Value exception(isolate, try_catch->Exception());
  38. const char *exception_string = ToCString(exception);
  39. v8::Local<v8::Message> tc_message = try_catch->Message();
  40. const char *filename_string, *sourceline_string;
  41. char *message_string;
  42. object_init_ex(return_value, php_ce_v8js_script_exception);
  43. #if PHP_VERSION_ID >= 80000
  44. #define PHPV8_EXPROP(type, name, value) \
  45. zend_update_property##type(php_ce_v8js_script_exception, Z_OBJ_P(return_value), #name, sizeof(#name) - 1, value);
  46. #else
  47. #define PHPV8_EXPROP(type, name, value) \
  48. zend_update_property##type(php_ce_v8js_script_exception, return_value, #name, sizeof(#name) - 1, value);
  49. #endif
  50. if (tc_message.IsEmpty()) {
  51. spprintf(&message_string, 0, "%s", exception_string);
  52. }
  53. else
  54. {
  55. v8::String::Utf8Value filename(isolate, tc_message->GetScriptResourceName());
  56. filename_string = ToCString(filename);
  57. PHPV8_EXPROP(_string, JsFileName, filename_string);
  58. v8::MaybeLocal<v8::String> maybe_sourceline = tc_message->GetSourceLine(context);
  59. if (!maybe_sourceline.IsEmpty()) {
  60. v8::String::Utf8Value sourceline(isolate, maybe_sourceline.ToLocalChecked());
  61. sourceline_string = ToCString(sourceline);
  62. PHPV8_EXPROP(_string, JsSourceLine, sourceline_string);
  63. }
  64. v8::Maybe<int> linenum = tc_message->GetLineNumber(context);
  65. if (linenum.IsJust()) {
  66. PHPV8_EXPROP(_long, JsLineNumber, linenum.FromJust());
  67. }
  68. v8::Maybe<int> start_col = tc_message->GetStartColumn(context);
  69. if (start_col.IsJust()) {
  70. PHPV8_EXPROP(_long, JsStartColumn, start_col.FromJust());
  71. }
  72. v8::Maybe<int> end_col = tc_message->GetEndColumn(context);
  73. if (end_col.IsJust()) {
  74. PHPV8_EXPROP(_long, JsEndColumn, end_col.FromJust());
  75. }
  76. spprintf(&message_string, 0, "%s:%d: %s", filename_string, linenum.FromMaybe(0), exception_string);
  77. v8::MaybeLocal<v8::Value> maybe_stacktrace = try_catch->StackTrace(context);
  78. if (!maybe_stacktrace.IsEmpty()) {
  79. v8::String::Utf8Value stacktrace(isolate, maybe_stacktrace.ToLocalChecked());
  80. PHPV8_EXPROP(_string, JsTrace, ToCString(stacktrace));
  81. }
  82. v8::Local<v8::Object> error_object;
  83. if(try_catch->Exception()->IsObject() && try_catch->Exception()->ToObject(context).ToLocal(&error_object) && error_object->InternalFieldCount() == 2) {
  84. zend_object *php_exception = reinterpret_cast<zend_object *>(error_object->GetAlignedPointerFromInternalField(1));
  85. zend_class_entry *exception_ce = zend_exception_get_default();
  86. if (instanceof_function(php_exception->ce, exception_ce)) {
  87. #ifdef GC_ADDREF
  88. GC_ADDREF(php_exception);
  89. #else
  90. ++GC_REFCOUNT(php_exception);
  91. #endif
  92. zend_exception_set_previous(Z_OBJ_P(return_value), php_exception);
  93. }
  94. }
  95. }
  96. PHPV8_EXPROP(_string, message, message_string);
  97. efree(message_string);
  98. }
  99. /* }}} */
  100. void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch) /* {{{ */
  101. {
  102. v8::String::Utf8Value exception(isolate, try_catch->Exception());
  103. const char *exception_string = ToCString(exception);
  104. zval zexception;
  105. if (try_catch->Message().IsEmpty()) {
  106. zend_throw_exception(php_ce_v8js_script_exception, (char *) exception_string, 0);
  107. } else {
  108. v8js_create_script_exception(&zexception, isolate, try_catch);
  109. zend_throw_exception_object(&zexception);
  110. }
  111. }
  112. /* }}} */
  113. #if PHP_VERSION_ID >= 80000
  114. #define V8JS_EXCEPTION_METHOD(property) \
  115. static PHP_METHOD(V8JsScriptException, get##property) \
  116. { \
  117. zval *value, rv; \
  118. \
  119. if (zend_parse_parameters_none() == FAILURE) { \
  120. return; \
  121. } \
  122. value = zend_read_property(php_ce_v8js_script_exception, Z_OBJ_P(getThis()), #property, sizeof(#property) - 1, 0, &rv); \
  123. RETURN_ZVAL(value, 1, 0); \
  124. }
  125. #else
  126. #define V8JS_EXCEPTION_METHOD(property) \
  127. static PHP_METHOD(V8JsScriptException, get##property) \
  128. { \
  129. zval *value, rv; \
  130. \
  131. if (zend_parse_parameters_none() == FAILURE) { \
  132. return; \
  133. } \
  134. value = zend_read_property(php_ce_v8js_script_exception, getThis(), #property, sizeof(#property) - 1, 0, &rv); \
  135. RETURN_ZVAL(value, 1, 0); \
  136. }
  137. #endif
  138. /* {{{ proto string V8JsEScriptxception::getJsFileName()
  139. */
  140. V8JS_EXCEPTION_METHOD(JsFileName);
  141. /* }}} */
  142. /* {{{ proto string V8JsScriptException::getJsLineNumber()
  143. */
  144. V8JS_EXCEPTION_METHOD(JsLineNumber);
  145. /* }}} */
  146. /* {{{ proto string V8JsScriptException::getJsStartColumn()
  147. */
  148. V8JS_EXCEPTION_METHOD(JsStartColumn);
  149. /* }}} */
  150. /* {{{ proto string V8JsScriptException::getJsEndColumn()
  151. */
  152. V8JS_EXCEPTION_METHOD(JsEndColumn);
  153. /* }}} */
  154. /* {{{ proto string V8JsScriptException::getJsSourceLine()
  155. */
  156. V8JS_EXCEPTION_METHOD(JsSourceLine);
  157. /* }}} */
  158. /* {{{ proto string V8JsScriptException::getJsTrace()
  159. */
  160. V8JS_EXCEPTION_METHOD(JsTrace);
  161. /* }}} */
  162. ZEND_BEGIN_ARG_INFO(arginfo_v8jsscriptexception_no_args, 0)
  163. ZEND_END_ARG_INFO()
  164. static const zend_function_entry v8js_script_exception_methods[] = { /* {{{ */
  165. PHP_ME(V8JsScriptException, getJsFileName, arginfo_v8jsscriptexception_no_args, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
  166. PHP_ME(V8JsScriptException, getJsLineNumber, arginfo_v8jsscriptexception_no_args, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
  167. PHP_ME(V8JsScriptException, getJsStartColumn, arginfo_v8jsscriptexception_no_args, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
  168. PHP_ME(V8JsScriptException, getJsEndColumn, arginfo_v8jsscriptexception_no_args, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
  169. PHP_ME(V8JsScriptException, getJsSourceLine, arginfo_v8jsscriptexception_no_args, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
  170. PHP_ME(V8JsScriptException, getJsTrace, arginfo_v8jsscriptexception_no_args, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
  171. {NULL, NULL, NULL}
  172. };
  173. /* }}} */
  174. /* }}} V8JsScriptException */
  175. /* {{{ Class: V8JsException */
  176. static const zend_function_entry v8js_exception_methods[] = { /* {{{ */
  177. {NULL, NULL, NULL}
  178. };
  179. /* }}} */
  180. /* }}} V8JsException */
  181. /* {{{ Class: V8JsTimeLimitException */
  182. static const zend_function_entry v8js_time_limit_exception_methods[] = { /* {{{ */
  183. {NULL, NULL, NULL}
  184. };
  185. /* }}} */
  186. /* }}} V8JsTimeLimitException */
  187. /* {{{ Class: V8JsMemoryLimitException */
  188. static const zend_function_entry v8js_memory_limit_exception_methods[] = { /* {{{ */
  189. {NULL, NULL, NULL}
  190. };
  191. /* }}} */
  192. /* }}} V8JsMemoryLimitException */
  193. PHP_MINIT_FUNCTION(v8js_exceptions) /* {{{ */
  194. {
  195. zend_class_entry ce;
  196. /* V8JsException Class */
  197. INIT_CLASS_ENTRY(ce, "V8JsException", v8js_exception_methods);
  198. php_ce_v8js_exception = zend_register_internal_class_ex(&ce, spl_ce_RuntimeException);
  199. /* V8JsScriptException Class */
  200. INIT_CLASS_ENTRY(ce, "V8JsScriptException", v8js_script_exception_methods);
  201. php_ce_v8js_script_exception = zend_register_internal_class_ex(&ce, php_ce_v8js_exception);
  202. php_ce_v8js_script_exception->ce_flags |= ZEND_ACC_FINAL;
  203. /* Add custom JS specific properties */
  204. zend_declare_property_null(php_ce_v8js_script_exception, ZEND_STRL("JsFileName"), ZEND_ACC_PROTECTED);
  205. zend_declare_property_null(php_ce_v8js_script_exception, ZEND_STRL("JsLineNumber"), ZEND_ACC_PROTECTED);
  206. zend_declare_property_null(php_ce_v8js_script_exception, ZEND_STRL("JsStartColumn"), ZEND_ACC_PROTECTED);
  207. zend_declare_property_null(php_ce_v8js_script_exception, ZEND_STRL("JsEndColumn"), ZEND_ACC_PROTECTED);
  208. zend_declare_property_null(php_ce_v8js_script_exception, ZEND_STRL("JsSourceLine"), ZEND_ACC_PROTECTED);
  209. zend_declare_property_null(php_ce_v8js_script_exception, ZEND_STRL("JsTrace"), ZEND_ACC_PROTECTED);
  210. /* V8JsTimeLimitException Class */
  211. INIT_CLASS_ENTRY(ce, "V8JsTimeLimitException", v8js_time_limit_exception_methods);
  212. php_ce_v8js_time_limit_exception = zend_register_internal_class_ex(&ce, php_ce_v8js_exception);
  213. php_ce_v8js_time_limit_exception->ce_flags |= ZEND_ACC_FINAL;
  214. /* V8JsMemoryLimitException Class */
  215. INIT_CLASS_ENTRY(ce, "V8JsMemoryLimitException", v8js_memory_limit_exception_methods);
  216. php_ce_v8js_memory_limit_exception = zend_register_internal_class_ex(&ce, php_ce_v8js_exception);
  217. php_ce_v8js_memory_limit_exception->ce_flags |= ZEND_ACC_FINAL;
  218. return SUCCESS;
  219. } /* }}} */
  220. /*
  221. * Local variables:
  222. * tab-width: 4
  223. * c-basic-offset: 4
  224. * indent-tabs-mode: t
  225. * End:
  226. * vim600: noet sw=4 ts=4 fdm=marker
  227. * vim<600: noet sw=4 ts=4
  228. */