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()->isame(s_call_user_func
.get())) return false;
88 if (func
->name()->isame(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
,
119 Variant(VarNR(const_cast<StringData
*>(func
->name()))));
120 init
.set(s_line_idx
, s_line
, line
);
121 result
= init
.toArray();
126 * hphp_debug_caller_info - returns an array of info about the "caller"
128 * For clarity, we refer to the function that called hphp_debug_caller_info()
129 * as the "callee", and we refer to the function that called the callee as
132 * This function returns an array containing keys "file", "function", "line" and
133 * optionally "class" which indicate the filename, function, line number and
134 * class name (if in class context) where the "caller" called the "callee".
136 Array
HHVM_FUNCTION(hphp_debug_caller_info
) {
137 Array result
= empty_dict_array();
138 bool skipped
= false;
139 walkStack([&] (const BTFrame
& frm
) {
140 return hphp_debug_caller_info_impl(
141 result
, skipped
, frm
.func(), frm
.bcOff());
146 int64_t HHVM_FUNCTION(hphp_debug_backtrace_hash
, int64_t options
/* = 0 */) {
147 return createBacktraceHash(
148 options
& k_DEBUG_BACKTRACE_HASH_CONSIDER_METADATA
152 void HHVM_FUNCTION(debug_print_backtrace
, int64_t options
/* = 0 */,
153 int64_t limit
/* = 0 */) {
154 bool ignore_args
= options
& k_DEBUG_BACKTRACE_IGNORE_ARGS
;
155 g_context
->write(debug_string_backtrace(false, ignore_args
, limit
));
158 String
stringify_backtrace(const Array
& bt
, bool ignore_args
) {
161 for (ArrayIter it
= bt
.begin(); !it
.end(); it
.next(), i
++) {
162 Array frame
= it
.second().toArray();
165 if (i
< 10) buf
.append(' ');
167 if (frame
.exists(s_class
)) {
168 buf
.append(tvCastToString(frame
->get(s_class
)));
169 buf
.append(tvCastToString(frame
->get(s_type
)));
171 buf
.append(tvCastToString(frame
->get(s_function
)));
175 for (ArrayIter
argsIt(tvCastToArrayLike(frame
->get(s_args
)));
184 buf
.append(argsIt
.second().toString());
185 } catch (FatalErrorException
& fe
) {
186 buf
.append(fe
.getMessage());
191 if (frame
.exists(s_file
)) {
192 buf
.append(" called at [");
193 buf
.append(tvCastToString(frame
->get(s_file
)));
195 buf
.append(tvCastToString(frame
->get(s_line
)));
203 String
debug_string_backtrace(bool skip
, bool ignore_args
/* = false */,
204 int64_t limit
/* = 0 */) {
206 bt
= createBacktrace(BacktraceArgs()
208 .ignoreArgs(ignore_args
)
210 return stringify_backtrace(bt
, ignore_args
);
213 Array
HHVM_FUNCTION(error_get_last
) {
214 String lastError
= g_context
->getLastError();
215 if (lastError
.isNull()) {
218 return make_dict_array(
219 s_type
, g_context
->getLastErrorNumber(),
220 s_message
, g_context
->getLastError(),
221 s_file
, g_context
->getLastErrorPath(),
222 s_line
, g_context
->getLastErrorLine()
226 bool HHVM_FUNCTION(error_log
, const String
& message
, int64_t message_type
/* = 0 */,
227 const Variant
& destination
/* = null */,
228 const Variant
& /*extra_headers*/ /* = null */) {
229 // error_log() should not invoke the user error handler,
230 // so we use Logger::Error() instead of raise_warning() or raise_error()
231 switch (message_type
) {
234 std::string
line(message
.data(),
236 message
.size() > (1<<19) ? (1<<19) : message
.size());
242 // open for append only
243 auto outfile
= HHVM_FN(fopen
)(destination
.toString(), "a");
244 if (outfile
.isNull()) {
245 Logger::Error("can't open error_log file!\n");
248 HHVM_FN(fwrite
)(outfile
.toResource(), message
);
249 HHVM_FN(fclose
)(outfile
.toResource());
252 case 2: // not used per PHP
254 Logger::Error("error_log does not support message_type %ld!", message_type
);
260 int64_t HHVM_FUNCTION(error_reporting
, const Variant
& level
/* = null */) {
261 auto& id
= RequestInfo::s_requestInfo
.getNoCheck()->m_reqInjectionData
;
262 int oldErrorReportingLevel
= id
.getErrorReportingLevel();
263 if (!level
.isNull()) {
264 id
.setErrorReportingLevel(level
.toInt32());
266 return oldErrorReportingLevel
;
269 bool HHVM_FUNCTION(restore_error_handler
) {
270 g_context
->popUserErrorHandler();
274 bool HHVM_FUNCTION(restore_exception_handler
) {
275 g_context
->popUserExceptionHandler();
279 Variant
HHVM_FUNCTION(set_error_handler
, const Variant
& error_handler
,
280 int64_t error_types
/* = ErrorMode::PHP_ALL | STRICT */) {
281 if (!is_null(error_handler
.asTypedValue())) {
282 return g_context
->pushUserErrorHandler(error_handler
, error_types
);
284 g_context
->clearUserErrorHandlers();
285 return init_null_variant
;
289 Variant
HHVM_FUNCTION(set_exception_handler
, const Variant
& exception_handler
) {
290 return g_context
->pushUserExceptionHandler(exception_handler
);
293 void HHVM_FUNCTION(hphp_set_error_page
, const String
& page
) {
294 g_context
->setErrorPage(page
);
297 void HHVM_FUNCTION(hphp_throw_fatal_error
, const String
& error_msg
) {
298 std::string msg
= error_msg
.data();
302 void HHVM_FUNCTION(hphp_clear_unflushed
) {
303 g_context
->obEndAll();
304 g_context
->obStart();
305 g_context
->obProtect(true);
308 bool HHVM_FUNCTION(trigger_error
, const String
& error_msg
,
309 int64_t error_type
/* = ErrorMode::USER_NOTICE */) {
310 std::string msg
= error_msg
.data(); // not toCppString()
311 if (UNLIKELY(g_context
->getThrowAllErrors())) {
312 throw Exception(folly::sformat("throwAllErrors: {}", error_type
));
314 if (error_type
== (int)ErrorMode::USER_ERROR
) {
315 g_context
->handleError(msg
, error_type
, true,
316 ExecutionContext::ErrorThrowMode::IfUnhandled
,
320 if (error_type
== (int)ErrorMode::USER_WARNING
) {
321 g_context
->handleError(msg
, error_type
, true,
322 ExecutionContext::ErrorThrowMode::Never
,
326 if (error_type
== (int)ErrorMode::USER_NOTICE
) {
327 g_context
->handleError(msg
, error_type
, true,
328 ExecutionContext::ErrorThrowMode::Never
,
332 if (error_type
== (int)ErrorMode::USER_DEPRECATED
) {
333 g_context
->handleError(msg
, error_type
, true,
334 ExecutionContext::ErrorThrowMode::Never
,
338 if (error_type
== (int)ErrorMode::STRICT
) {
339 // So that we can raise strict warnings for mismatched
340 // params in FCallBuiltin
341 raise_strict_warning(msg
);
345 auto const f
= fromCaller(
346 [] (const BTFrame
& frm
) { return frm
.func(); }
349 if (f
&& f
->isBuiltin()) {
350 if (error_type
== (int)ErrorMode::ERROR
) {
351 raise_error_without_first_frame(msg
);
354 if (error_type
== (int)ErrorMode::WARNING
) {
355 raise_warning_without_first_frame(msg
);
358 if (error_type
== (int)ErrorMode::NOTICE
) {
359 raise_notice_without_first_frame(msg
);
362 if (error_type
== (int)ErrorMode::PHP_DEPRECATED
) {
363 raise_deprecated_without_first_frame(msg
);
366 if (error_type
== (int)ErrorMode::RECOVERABLE_ERROR
) {
367 raise_recoverable_error_without_first_frame(msg
);
371 raise_warning("Invalid error type specified");
375 bool HHVM_FUNCTION(trigger_sampled_error
, const String
& error_msg
,
377 int64_t error_type
/* = (int)ErrorMode::USER_NOTICE */) {
378 if (!folly::Random::oneIn(sample_rate
)) {
381 return HHVM_FN(trigger_error
)(error_msg
, error_type
);
384 bool HHVM_FUNCTION(user_error
, const String
& error_msg
,
385 int64_t error_type
/* = (int)ErrorMode::USER_NOTICE */) {
386 return HHVM_FN(trigger_error
)(error_msg
, error_type
);
389 ///////////////////////////////////////////////////////////////////////////////
391 Array
HHVM_FUNCTION(HH_deferred_errors
) {
392 return g_context
->releaseDeferredErrors();
395 ///////////////////////////////////////////////////////////////////////////////
397 void StandardExtension::initErrorFunc() {
398 HHVM_FE(debug_backtrace
);
399 HHVM_FE(hphp_debug_caller_info
);
400 HHVM_FE(hphp_debug_backtrace_hash
);
401 HHVM_FE(debug_print_backtrace
);
402 HHVM_FE(error_get_last
);
404 HHVM_FE(error_reporting
);
405 HHVM_FE(restore_error_handler
);
406 HHVM_FE(restore_exception_handler
);
407 HHVM_FE(set_error_handler
);
408 HHVM_FE(set_exception_handler
);
409 HHVM_FE(hphp_set_error_page
);
410 HHVM_FE(hphp_throw_fatal_error
);
411 HHVM_FE(hphp_clear_unflushed
);
412 HHVM_FE(trigger_error
);
413 HHVM_FE(trigger_sampled_error
);
415 HHVM_FALIAS(HH
\\deferred_errors
, HH_deferred_errors
);
416 HHVM_RC_INT(DEBUG_BACKTRACE_PROVIDE_OBJECT
, k_DEBUG_BACKTRACE_PROVIDE_OBJECT
);
417 HHVM_RC_INT(DEBUG_BACKTRACE_IGNORE_ARGS
, k_DEBUG_BACKTRACE_IGNORE_ARGS
);
418 HHVM_RC_INT(DEBUG_BACKTRACE_PROVIDE_METADATA
,
419 k_DEBUG_BACKTRACE_PROVIDE_METADATA
);
420 HHVM_RC_INT(DEBUG_BACKTRACE_HASH_CONSIDER_METADATA
,
421 k_DEBUG_BACKTRACE_HASH_CONSIDER_METADATA
);
422 HHVM_RC_INT(E_ERROR
, (int)ErrorMode::ERROR
);
423 HHVM_RC_INT(E_WARNING
, (int)ErrorMode::WARNING
);
424 HHVM_RC_INT(E_PARSE
, (int)ErrorMode::PARSE
);
425 HHVM_RC_INT(E_NOTICE
, (int)ErrorMode::NOTICE
);
426 HHVM_RC_INT(E_CORE_ERROR
, (int)ErrorMode::CORE_ERROR
);
427 HHVM_RC_INT(E_CORE_WARNING
, (int)ErrorMode::CORE_WARNING
);
428 HHVM_RC_INT(E_COMPILE_ERROR
, (int)ErrorMode::COMPILE_ERROR
);
429 HHVM_RC_INT(E_COMPILE_WARNING
, (int)ErrorMode::COMPILE_WARNING
);
430 HHVM_RC_INT(E_USER_ERROR
, (int)ErrorMode::USER_ERROR
);
431 HHVM_RC_INT(E_USER_WARNING
, (int)ErrorMode::USER_WARNING
);
432 HHVM_RC_INT(E_USER_NOTICE
, (int)ErrorMode::USER_NOTICE
);
433 HHVM_RC_INT(E_STRICT
, (int)ErrorMode::STRICT
);
434 HHVM_RC_INT(E_RECOVERABLE_ERROR
, (int)ErrorMode::RECOVERABLE_ERROR
);
435 HHVM_RC_INT(E_DEPRECATED
, (int)ErrorMode::PHP_DEPRECATED
);
436 HHVM_RC_INT(E_USER_DEPRECATED
, (int)ErrorMode::USER_DEPRECATED
);
437 HHVM_RC_INT(E_ALL
, (int)ErrorMode::PHP_ALL
| (int)ErrorMode::STRICT
);
439 HHVM_RC_INT(E_HHVM_FATAL_ERROR
, (int)ErrorMode::FATAL_ERROR
);
441 loadSystemlib("std_errorfunc");