2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
17 #include "hphp/runtime/ext/std/ext_std_errorfunc.h"
21 #include <folly/Format.h>
22 #include <folly/Likely.h>
23 #include <folly/Random.h>
25 #include "hphp/runtime/base/array-init.h"
26 #include "hphp/runtime/base/array-iterator.h"
27 #include "hphp/runtime/base/backtrace.h"
28 #include "hphp/runtime/base/bespoke-runtime.h"
29 #include "hphp/runtime/base/builtin-functions.h"
30 #include "hphp/runtime/base/exceptions.h"
31 #include "hphp/runtime/base/execution-context.h"
32 #include "hphp/runtime/base/string-buffer.h"
33 #include "hphp/runtime/base/request-info.h"
34 #include "hphp/runtime/base/backtrace.h"
35 #include "hphp/runtime/ext/std/ext_std_file.h"
36 #include "hphp/util/logger.h"
40 ///////////////////////////////////////////////////////////////////////////////
45 s_function("function"),
50 s_call_user_func("call_user_func"),
51 s_call_user_func_array("call_user_func_array"),
52 s_hphp_debug_caller_info("hphp_debug_caller_info");
54 ///////////////////////////////////////////////////////////////////////////////
56 const int64_t k_DEBUG_BACKTRACE_PROVIDE_OBJECT
= (1 << 0);
57 const int64_t k_DEBUG_BACKTRACE_IGNORE_ARGS
= (1 << 1);
58 const int64_t k_DEBUG_BACKTRACE_PROVIDE_METADATA
= (1 << 16);
60 const int64_t k_DEBUG_BACKTRACE_HASH_CONSIDER_METADATA
= (1 << 0);
63 Array
HHVM_FUNCTION(debug_backtrace
, int64_t options
/* = 1 */,
64 int64_t limit
/* = 0 */) {
65 bool provide_object
= options
& k_DEBUG_BACKTRACE_PROVIDE_OBJECT
;
66 bool provide_metadata
= options
& k_DEBUG_BACKTRACE_PROVIDE_METADATA
;
67 bool ignore_args
= options
& k_DEBUG_BACKTRACE_IGNORE_ARGS
;
68 return createBacktrace(BacktraceArgs()
69 .withThis(provide_object
)
70 .withMetadata(provide_metadata
)
71 .ignoreArgs(ignore_args
)
75 ArrayData
* debug_backtrace_jit(int64_t options
) {
76 return HHVM_FN(debug_backtrace
)(options
).detach();
79 bool hphp_debug_caller_info_impl(
80 Array
& result
, bool& skipped
, const Func
* func
, Offset offset
) {
81 if (!skipped
&& func
->isSkipFrame()) return false;
87 if (func
->name() == s_call_user_func
.get()) return false;
88 if (func
->name() == s_call_user_func_array
.get()) return false;
90 auto const line
= func
->getLineNumber(offset
);
91 if (line
== -1) return false;
93 static constexpr auto s_file_idx
= 0;
94 static constexpr auto s_line_idx
= 1;
95 static constexpr auto s_class_idx
= 2;
96 static constexpr auto s_function_idx
= 3;
97 static const RuntimeStruct::FieldIndexVector s_fields
= {
100 {s_class_idx
, s_class
},
101 {s_function_idx
, s_function
},
103 static auto const s_struct
=
104 RuntimeStruct::registerRuntimeStruct(s_hphp_debug_caller_info
, s_fields
);
106 auto const cls
= func
->cls();
107 auto const path
= func
->originalFilename() ?
108 func
->originalFilename() : func
->unit()->filepath();
110 auto const has_cls
= cls
&& !func
->isClosureBody();
111 StructDictInit
init(s_struct
, has_cls
? 4 : 3);
113 init
.set(s_class_idx
, s_class
,
114 Variant(VarNR(const_cast<StringData
*>(cls
->name()))));
116 init
.set(s_file_idx
, s_file
,
117 Variant(VarNR(const_cast<StringData
*>(path
))));
118 init
.set(s_function_idx
, s_function
, func
->nameWithClosureName());
119 init
.set(s_line_idx
, s_line
, line
);
120 result
= init
.toArray();
125 * hphp_debug_caller_info - returns an array of info about the "caller"
127 * For clarity, we refer to the function that called hphp_debug_caller_info()
128 * as the "callee", and we refer to the function that called the callee as
131 * This function returns an array containing keys "file", "function", "line" and
132 * optionally "class" which indicate the filename, function, line number and
133 * class name (if in class context) where the "caller" called the "callee".
135 ArrayRet
HHVM_FUNCTION(hphp_debug_caller_info
) {
136 Array result
= empty_dict_array();
137 bool skipped
= false;
138 walkStack([&] (const BTFrame
& frm
) {
139 return hphp_debug_caller_info_impl(
140 result
, skipped
, frm
.func(), frm
.bcOff());
146 bool hphp_debug_caller_identifier_impl(
147 String
& result
, bool& skipped
, const Func
* func
) {
148 if (!skipped
&& func
->isSkipFrame()) return false;
154 if (func
->name()->fsame(s_call_user_func
.get())) return false;
155 if (func
->name()->fsame(s_call_user_func_array
.get())) return false;
157 result
= func
->fullNameWithClosureName();
162 * hphp_debug_caller_identifier - returns the full function name of
165 * For clarity, we refer to the function that called
166 * hphp_debug_caller_identifier() as the "callee", and we refer to the
167 * function that called the callee as the "caller".
169 String
HHVM_FUNCTION(hphp_debug_caller_identifier
) {
170 String result
= empty_string();
171 bool skipped
= false;
172 walkStack([&] (const BTFrame
& frm
) {
173 return hphp_debug_caller_identifier_impl(
174 result
, skipped
, frm
.func());
179 int64_t HHVM_FUNCTION(hphp_debug_backtrace_hash
, int64_t options
/* = 0 */) {
180 return createBacktraceHash(
181 options
& k_DEBUG_BACKTRACE_HASH_CONSIDER_METADATA
185 void HHVM_FUNCTION(debug_print_backtrace
, int64_t options
/* = 0 */,
186 int64_t limit
/* = 0 */) {
187 bool ignore_args
= options
& k_DEBUG_BACKTRACE_IGNORE_ARGS
;
188 g_context
->write(debug_string_backtrace(false, ignore_args
, limit
));
191 String
stringify_backtrace(const Array
& bt
, bool ignore_args
) {
194 for (ArrayIter it
= bt
.begin(); !it
.end(); it
.next(), i
++) {
195 Array frame
= it
.second().toArray();
198 if (i
< 10) buf
.append(' ');
200 if (frame
.exists(s_class
)) {
201 buf
.append(tvCastToString(frame
->get(s_class
)));
202 buf
.append(tvCastToString(frame
->get(s_type
)));
204 buf
.append(tvCastToString(frame
->get(s_function
)));
208 for (ArrayIter
argsIt(tvCastToArrayLike(frame
->get(s_args
)));
217 buf
.append(argsIt
.second().toString());
218 } catch (FatalErrorException
& fe
) {
219 buf
.append(fe
.getMessage());
224 if (frame
.exists(s_file
)) {
225 buf
.append(" called at [");
226 buf
.append(tvCastToString(frame
->get(s_file
)));
228 buf
.append(tvCastToString(frame
->get(s_line
)));
236 String
debug_string_backtrace(bool skip
, bool ignore_args
/* = false */,
237 int64_t limit
/* = 0 */) {
239 bt
= createBacktrace(BacktraceArgs()
241 .ignoreArgs(ignore_args
)
243 return stringify_backtrace(bt
, ignore_args
);
246 Array
HHVM_FUNCTION(error_get_last
) {
247 String lastError
= g_context
->getLastError();
248 if (lastError
.isNull()) {
251 return make_dict_array(
252 s_type
, g_context
->getLastErrorNumber(),
253 s_message
, g_context
->getLastError(),
254 s_file
, g_context
->getLastErrorPath(),
255 s_line
, g_context
->getLastErrorLine()
259 bool HHVM_FUNCTION(error_log
, const String
& message
, int64_t message_type
/* = 0 */,
260 const Variant
& destination
/* = null */,
261 const Variant
& /*extra_headers*/ /* = null */) {
262 // error_log() should not invoke the user error handler,
263 // so we use Logger::Error() instead of raise_warning() or raise_error()
264 switch (message_type
) {
267 std::string
line(message
.data(),
269 message
.size() > (1<<19) ? (1<<19) : message
.size());
275 // open for append only
276 auto outfile
= HHVM_FN(fopen
)(destination
.toString(), "a");
277 if (outfile
.isNull()) {
278 Logger::Error("can't open error_log file!\n");
281 HHVM_FN(fwrite
)(outfile
.toResource(), message
);
282 HHVM_FN(fclose
)(outfile
.toResource());
285 case 2: // not used per PHP
287 Logger::Error("error_log does not support message_type %ld!", message_type
);
293 int64_t HHVM_FUNCTION(error_reporting
, const Variant
& level
/* = null */) {
294 auto& id
= RequestInfo::s_requestInfo
.getNoCheck()->m_reqInjectionData
;
295 int oldErrorReportingLevel
= id
.getErrorReportingLevel();
296 if (!level
.isNull()) {
297 id
.setErrorReportingLevel((int)level
.toInt64());
299 return oldErrorReportingLevel
;
302 bool HHVM_FUNCTION(restore_error_handler
) {
303 g_context
->popUserErrorHandler();
307 bool HHVM_FUNCTION(restore_exception_handler
) {
308 g_context
->popUserExceptionHandler();
312 Variant
HHVM_FUNCTION(set_error_handler
, const Variant
& error_handler
,
313 int64_t error_types
/* = ErrorMode::PHP_ALL | STRICT */) {
314 if (!is_null(error_handler
.asTypedValue())) {
315 return g_context
->pushUserErrorHandler(error_handler
, error_types
);
317 g_context
->clearUserErrorHandlers();
318 return init_null_variant
;
322 Variant
HHVM_FUNCTION(set_exception_handler
, const Variant
& exception_handler
) {
323 return g_context
->pushUserExceptionHandler(exception_handler
);
326 void HHVM_FUNCTION(hphp_set_error_page
, const String
& page
) {
327 g_context
->setErrorPage(page
);
330 void HHVM_FUNCTION(hphp_throw_fatal_error
, const String
& error_msg
) {
331 std::string msg
= error_msg
.data();
335 void HHVM_FUNCTION(hphp_clear_unflushed
) {
336 g_context
->obEndAll();
337 g_context
->obStart();
338 g_context
->obProtect(true);
341 bool HHVM_FUNCTION(trigger_error
, const String
& error_msg
,
342 int64_t error_type
/* = ErrorMode::USER_NOTICE */) {
343 std::string msg
= error_msg
.data(); // not toCppString()
344 if (UNLIKELY(g_context
->getThrowAllErrors())) {
345 throw Exception(folly::sformat("throwAllErrors: {}", error_type
));
347 if (error_type
== (int)ErrorMode::USER_ERROR
) {
348 g_context
->handleError(msg
, error_type
, true,
349 ExecutionContext::ErrorThrowMode::IfUnhandled
,
353 if (error_type
== (int)ErrorMode::USER_WARNING
) {
354 g_context
->handleError(msg
, error_type
, true,
355 ExecutionContext::ErrorThrowMode::Never
,
359 if (error_type
== (int)ErrorMode::USER_NOTICE
) {
360 g_context
->handleError(msg
, error_type
, true,
361 ExecutionContext::ErrorThrowMode::Never
,
365 if (error_type
== (int)ErrorMode::USER_DEPRECATED
) {
366 g_context
->handleError(msg
, error_type
, true,
367 ExecutionContext::ErrorThrowMode::Never
,
371 if (error_type
== (int)ErrorMode::STRICT
) {
372 // So that we can raise strict warnings for mismatched
373 // params in FCallBuiltin
374 raise_strict_warning(msg
);
378 auto const f
= fromCaller(
379 [] (const BTFrame
& frm
) { return frm
.func(); }
382 if (f
&& f
->isBuiltin()) {
383 if (error_type
== (int)ErrorMode::ERROR
) {
384 raise_error_without_first_frame(msg
);
387 if (error_type
== (int)ErrorMode::WARNING
) {
388 raise_warning_without_first_frame(msg
);
391 if (error_type
== (int)ErrorMode::NOTICE
) {
392 raise_notice_without_first_frame(msg
);
395 if (error_type
== (int)ErrorMode::PHP_DEPRECATED
) {
396 raise_deprecated_without_first_frame(msg
);
399 if (error_type
== (int)ErrorMode::RECOVERABLE_ERROR
) {
400 raise_recoverable_error_without_first_frame(msg
);
404 raise_warning("Invalid error type specified");
408 bool HHVM_FUNCTION(trigger_sampled_error
, const String
& error_msg
,
410 int64_t error_type
/* = (int)ErrorMode::USER_NOTICE */) {
411 if (!folly::Random::oneIn(sample_rate
)) {
414 return HHVM_FN(trigger_error
)(error_msg
, error_type
);
417 bool HHVM_FUNCTION(user_error
, const String
& error_msg
,
418 int64_t error_type
/* = (int)ErrorMode::USER_NOTICE */) {
419 return HHVM_FN(trigger_error
)(error_msg
, error_type
);
422 ///////////////////////////////////////////////////////////////////////////////
424 Array
HHVM_FUNCTION(HH_deferred_errors
) {
425 return g_context
->releaseDeferredErrors();
428 ///////////////////////////////////////////////////////////////////////////////
430 void StandardExtension::registerNativeErrorFunc() {
431 HHVM_FE(debug_backtrace
);
432 HHVM_FE(hphp_debug_caller_info
);
433 HHVM_FE(hphp_debug_caller_identifier
);
434 HHVM_FE(hphp_debug_backtrace_hash
);
435 HHVM_FE(debug_print_backtrace
);
436 HHVM_FE(error_get_last
);
438 HHVM_FE(error_reporting
);
439 HHVM_FE(restore_error_handler
);
440 HHVM_FE(restore_exception_handler
);
441 HHVM_FE(set_error_handler
);
442 HHVM_FE(set_exception_handler
);
443 HHVM_FE(hphp_set_error_page
);
444 HHVM_FE(hphp_throw_fatal_error
);
445 HHVM_FE(hphp_clear_unflushed
);
446 HHVM_FE(trigger_error
);
447 HHVM_FE(trigger_sampled_error
);
449 HHVM_FALIAS(HH
\\deferred_errors
, HH_deferred_errors
);
450 HHVM_RC_INT(DEBUG_BACKTRACE_PROVIDE_OBJECT
, k_DEBUG_BACKTRACE_PROVIDE_OBJECT
);
451 HHVM_RC_INT(DEBUG_BACKTRACE_IGNORE_ARGS
, k_DEBUG_BACKTRACE_IGNORE_ARGS
);
452 HHVM_RC_INT(DEBUG_BACKTRACE_PROVIDE_METADATA
,
453 k_DEBUG_BACKTRACE_PROVIDE_METADATA
);
454 HHVM_RC_INT(DEBUG_BACKTRACE_HASH_CONSIDER_METADATA
,
455 k_DEBUG_BACKTRACE_HASH_CONSIDER_METADATA
);
456 HHVM_RC_INT(E_ERROR
, (int)ErrorMode::ERROR
);
457 HHVM_RC_INT(E_WARNING
, (int)ErrorMode::WARNING
);
458 HHVM_RC_INT(E_PARSE
, (int)ErrorMode::PARSE
);
459 HHVM_RC_INT(E_NOTICE
, (int)ErrorMode::NOTICE
);
460 HHVM_RC_INT(E_CORE_ERROR
, (int)ErrorMode::CORE_ERROR
);
461 HHVM_RC_INT(E_CORE_WARNING
, (int)ErrorMode::CORE_WARNING
);
462 HHVM_RC_INT(E_COMPILE_ERROR
, (int)ErrorMode::COMPILE_ERROR
);
463 HHVM_RC_INT(E_COMPILE_WARNING
, (int)ErrorMode::COMPILE_WARNING
);
464 HHVM_RC_INT(E_USER_ERROR
, (int)ErrorMode::USER_ERROR
);
465 HHVM_RC_INT(E_USER_WARNING
, (int)ErrorMode::USER_WARNING
);
466 HHVM_RC_INT(E_USER_NOTICE
, (int)ErrorMode::USER_NOTICE
);
467 HHVM_RC_INT(E_STRICT
, (int)ErrorMode::STRICT
);
468 HHVM_RC_INT(E_RECOVERABLE_ERROR
, (int)ErrorMode::RECOVERABLE_ERROR
);
469 HHVM_RC_INT(E_DEPRECATED
, (int)ErrorMode::PHP_DEPRECATED
);
470 HHVM_RC_INT(E_USER_DEPRECATED
, (int)ErrorMode::USER_DEPRECATED
);
471 HHVM_RC_INT(E_ALL
, (int)ErrorMode::PHP_ALL
| (int)ErrorMode::STRICT
);
473 HHVM_RC_INT(E_HHVM_FATAL_ERROR
, (int)ErrorMode::FATAL_ERROR
);