PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/base/execution-context.cpp

https://github.com/tstarling/hiphop-php
C++ | 784 lines | 652 code | 84 blank | 48 comment | 128 complexity | c670aae73feaee1fbdbffe2c7c9ef241 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/runtime/base/execution-context.h"
  17. #define __STDC_LIMIT_MACROS
  18. #include <cstdint>
  19. #include <algorithm>
  20. #include <list>
  21. #include <utility>
  22. #include "folly/MapUtil.h"
  23. #include "hphp/util/logger.h"
  24. #include "hphp/util/process.h"
  25. #include "hphp/util/text-color.h"
  26. #include "hphp/runtime/base/request-event-handler.h"
  27. #include "hphp/runtime/base/array-init.h"
  28. #include "hphp/runtime/base/debuggable.h"
  29. #include "hphp/runtime/base/array-iterator.h"
  30. #include "hphp/runtime/base/memory-manager.h"
  31. #include "hphp/runtime/base/sweepable.h"
  32. #include "hphp/runtime/server/server-stats.h"
  33. #include "hphp/runtime/base/request-local.h"
  34. #include "hphp/runtime/base/builtin-functions.h"
  35. #include "hphp/runtime/base/comparisons.h"
  36. #include "hphp/runtime/base/complex-types.h"
  37. #include "hphp/runtime/base/externals.h"
  38. #include "hphp/runtime/base/runtime-option.h"
  39. #include "hphp/runtime/base/type-conversions.h"
  40. #include "hphp/runtime/debugger/debugger.h"
  41. #include "hphp/runtime/base/file-repository.h"
  42. #include "hphp/runtime/ext/ext_string.h"
  43. #include "hphp/runtime/vm/jit/translator-inline.h"
  44. #include "hphp/runtime/vm/jit/translator.h"
  45. #include "hphp/runtime/vm/debugger-hook.h"
  46. #include "hphp/runtime/vm/event-hook.h"
  47. namespace HPHP {
  48. ///////////////////////////////////////////////////////////////////////////////
  49. IMPLEMENT_THREAD_LOCAL_NO_CHECK(ExecutionContext, g_context);
  50. ExecutionContext::ExecutionContext()
  51. : m_fp(nullptr)
  52. , m_pc(nullptr)
  53. , m_transport(nullptr)
  54. , m_cwd(Process::CurrentWorkingDirectory)
  55. , m_out(nullptr)
  56. , m_implicitFlush(false)
  57. , m_protectedLevel(0)
  58. , m_stdout(nullptr)
  59. , m_stdoutData(nullptr)
  60. , m_errorState(ExecutionContext::ErrorState::NoError)
  61. , m_lastErrorNum(0)
  62. , m_throwAllErrors(false)
  63. , m_vhost(nullptr)
  64. , m_globalVarEnv(nullptr)
  65. , m_lambdaCounter(0)
  66. , m_nesting(0)
  67. , m_breakPointFilter(nullptr)
  68. , m_lastLocFilter(nullptr)
  69. , m_dbgNoBreak(false)
  70. , m_coverPrevLine(-1)
  71. , m_coverPrevUnit(nullptr)
  72. , m_lastErrorPath("")
  73. , m_lastErrorLine(0)
  74. , m_executingSetprofileCallback(false)
  75. {
  76. // We want this to run on every request, instead of just once per thread
  77. auto max_mem = std::to_string(RuntimeOption::RequestMemoryMaxBytes);
  78. IniSetting::Set("memory_limit", max_mem);
  79. // This one is hot so we don't want to go through the ini_set() machinery to
  80. // change it in error_reporting(). Because of that, we have to set it back to
  81. // the default on every request.
  82. ThreadInfo::s_threadInfo.getNoCheck()->m_reqInjectionData.
  83. setErrorReportingLevel(RuntimeOption::RuntimeErrorReportingLevel);
  84. // Make sure any fields accessed from the TC are within a byte of
  85. // ExecutionContext's beginning.
  86. static_assert(offsetof(ExecutionContext, m_stack) <= 0xff,
  87. "m_stack offset too large");
  88. static_assert(offsetof(ExecutionContext, m_fp) <= 0xff,
  89. "m_fp offset too large");
  90. static_assert(offsetof(ExecutionContext, m_pc) <= 0xff,
  91. "m_pc offset too large");
  92. }
  93. ExecutionContext::~ExecutionContext() {
  94. // Discard any ConstInfo objects that were created to support reflection.
  95. for (ConstInfoMap::const_iterator it = m_constInfo.begin();
  96. it != m_constInfo.end(); ++it) {
  97. delete it->second;
  98. }
  99. // Discard all units that were created via create_function().
  100. for (auto& v : m_createdFuncs) delete v;
  101. delete m_breakPointFilter;
  102. delete m_lastLocFilter;
  103. obFlushAll();
  104. for (auto& b : m_buffers) delete b;
  105. }
  106. void ExecutionContext::backupSession() {
  107. m_shutdownsBackup = m_shutdowns;
  108. m_userErrorHandlersBackup = m_userErrorHandlers;
  109. m_userExceptionHandlersBackup = m_userExceptionHandlers;
  110. }
  111. void ExecutionContext::restoreSession() {
  112. m_shutdowns = m_shutdownsBackup;
  113. m_userErrorHandlers = m_userErrorHandlersBackup;
  114. m_userExceptionHandlers = m_userExceptionHandlersBackup;
  115. }
  116. ///////////////////////////////////////////////////////////////////////////////
  117. // system functions
  118. String ExecutionContext::getMimeType() const {
  119. String mimetype;
  120. if (m_transport) {
  121. mimetype = m_transport->getMimeType();
  122. }
  123. if (strncasecmp(mimetype.data(), "text/", 5) == 0) {
  124. int pos = mimetype.find(';');
  125. if (pos != String::npos) {
  126. mimetype = mimetype.substr(0, pos);
  127. }
  128. } else if (m_transport && m_transport->getUseDefaultContentType()) {
  129. mimetype =
  130. ThreadInfo::s_threadInfo->m_reqInjectionData.getDefaultMimeType();
  131. }
  132. return mimetype;
  133. }
  134. std::string ExecutionContext::getRequestUrl(size_t szLimit) {
  135. Transport* t = getTransport();
  136. std::string ret = t ? t->getUrl() : "";
  137. if (szLimit != std::string::npos) {
  138. ret = ret.substr(0, szLimit);
  139. }
  140. return ret;
  141. }
  142. void ExecutionContext::setContentType(const String& mimetype,
  143. const String& charset) {
  144. if (m_transport) {
  145. String contentType = mimetype;
  146. contentType += "; ";
  147. contentType += "charset=";
  148. contentType += charset;
  149. m_transport->addHeader("Content-Type", contentType.c_str());
  150. m_transport->setUseDefaultContentType(false);
  151. }
  152. }
  153. ///////////////////////////////////////////////////////////////////////////////
  154. // write()
  155. void ExecutionContext::write(const String& s) {
  156. write(s.data(), s.size());
  157. }
  158. void ExecutionContext::setStdout(PFUNC_STDOUT func, void *data) {
  159. m_stdout = func;
  160. m_stdoutData = data;
  161. }
  162. static void safe_stdout(const void *ptr, size_t size) {
  163. write(fileno(stdout), ptr, size);
  164. }
  165. void ExecutionContext::writeStdout(const char *s, int len) {
  166. if (m_stdout == nullptr) {
  167. if (s_stdout_color) {
  168. safe_stdout(s_stdout_color, strlen(s_stdout_color));
  169. safe_stdout(s, len);
  170. safe_stdout(ANSI_COLOR_END, strlen(ANSI_COLOR_END));
  171. } else {
  172. safe_stdout(s, len);
  173. }
  174. } else {
  175. m_stdout(s, len, m_stdoutData);
  176. }
  177. }
  178. void ExecutionContext::write(const char *s, int len) {
  179. if (m_out) {
  180. m_out->append(s, len);
  181. } else {
  182. writeStdout(s, len);
  183. }
  184. if (m_implicitFlush) flush();
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////
  187. // output buffers
  188. void ExecutionContext::obProtect(bool on) {
  189. m_protectedLevel = on ? m_buffers.size() : 0;
  190. }
  191. void ExecutionContext::obStart(const Variant& handler /* = null */) {
  192. OutputBuffer *ob = new OutputBuffer();
  193. ob->handler = handler;
  194. m_buffers.push_back(ob);
  195. resetCurrentBuffer();
  196. }
  197. String ExecutionContext::obCopyContents() {
  198. if (!m_buffers.empty()) {
  199. StringBuffer &oss = m_buffers.back()->oss;
  200. if (!oss.empty()) {
  201. return oss.copy();
  202. }
  203. }
  204. return "";
  205. }
  206. String ExecutionContext::obDetachContents() {
  207. if (!m_buffers.empty()) {
  208. StringBuffer &oss = m_buffers.back()->oss;
  209. if (!oss.empty()) {
  210. return oss.detach();
  211. }
  212. }
  213. return "";
  214. }
  215. int ExecutionContext::obGetContentLength() {
  216. if (m_buffers.empty()) {
  217. return 0;
  218. }
  219. return m_buffers.back()->oss.size();
  220. }
  221. void ExecutionContext::obClean() {
  222. if (!m_buffers.empty()) {
  223. m_buffers.back()->oss.clear();
  224. }
  225. }
  226. bool ExecutionContext::obFlush() {
  227. assert(m_protectedLevel >= 0);
  228. if ((int)m_buffers.size() > m_protectedLevel) {
  229. std::list<OutputBuffer*>::const_iterator iter = m_buffers.end();
  230. OutputBuffer *last = *(--iter);
  231. const int flag = PHP_OUTPUT_HANDLER_START | PHP_OUTPUT_HANDLER_END;
  232. if (iter != m_buffers.begin()) {
  233. OutputBuffer *prev = *(--iter);
  234. if (last->handler.isNull()) {
  235. prev->oss.absorb(last->oss);
  236. } else {
  237. try {
  238. Variant tout = vm_call_user_func(
  239. last->handler, make_packed_array(last->oss.detach(), flag)
  240. );
  241. prev->oss.append(tout.toString());
  242. last->oss.clear();
  243. } catch (...) {
  244. prev->oss.absorb(last->oss);
  245. }
  246. }
  247. return true;
  248. }
  249. if (!last->handler.isNull()) {
  250. try {
  251. Variant tout = vm_call_user_func(
  252. last->handler, make_packed_array(last->oss.detach(), flag)
  253. );
  254. String sout = tout.toString();
  255. writeStdout(sout.data(), sout.size());
  256. last->oss.clear();
  257. return true;
  258. } catch (...) {}
  259. }
  260. writeStdout(last->oss.data(), last->oss.size());
  261. last->oss.clear();
  262. return true;
  263. }
  264. return false;
  265. }
  266. void ExecutionContext::obFlushAll() {
  267. while (obFlush()) { obEnd();}
  268. }
  269. bool ExecutionContext::obEnd() {
  270. assert(m_protectedLevel >= 0);
  271. if ((int)m_buffers.size() > m_protectedLevel) {
  272. delete m_buffers.back();
  273. m_buffers.pop_back();
  274. resetCurrentBuffer();
  275. if (m_implicitFlush) flush();
  276. return true;
  277. }
  278. if (m_implicitFlush) flush();
  279. return false;
  280. }
  281. void ExecutionContext::obEndAll() {
  282. while (obEnd()) {}
  283. }
  284. int ExecutionContext::obGetLevel() {
  285. assert((int)m_buffers.size() >= m_protectedLevel);
  286. return m_buffers.size() - m_protectedLevel;
  287. }
  288. const StaticString
  289. s_level("level"),
  290. s_type("type"),
  291. s_name("name"),
  292. s_args("args"),
  293. s_default_output_handler("default output handler");
  294. Array ExecutionContext::obGetStatus(bool full) {
  295. Array ret = Array::Create();
  296. std::list<OutputBuffer*>::const_iterator iter = m_buffers.begin();
  297. ++iter; // skip over the fake outermost buffer
  298. int level = 0;
  299. for (; iter != m_buffers.end(); ++iter, ++level) {
  300. Array status;
  301. status.set(s_level, level);
  302. if (level < m_protectedLevel) {
  303. status.set(s_type, 1);
  304. status.set(s_name, s_default_output_handler);
  305. } else {
  306. status.set(s_type, 0);
  307. status.set(s_name, (*iter)->handler);
  308. }
  309. if (full) {
  310. ret.append(status);
  311. } else {
  312. ret = std::move(status);
  313. }
  314. }
  315. return ret;
  316. }
  317. void ExecutionContext::obSetImplicitFlush(bool on) {
  318. m_implicitFlush = on;
  319. }
  320. Array ExecutionContext::obGetHandlers() {
  321. Array ret;
  322. for (auto& ob : m_buffers) {
  323. auto& handler = ob->handler;
  324. ret.append(handler.isNull() ? s_default_output_handler : handler);
  325. }
  326. return ret;
  327. }
  328. void ExecutionContext::flush() {
  329. if (m_buffers.empty()) {
  330. fflush(stdout);
  331. } else if (RuntimeOption::EnableEarlyFlush && m_protectedLevel &&
  332. (m_transport == nullptr ||
  333. (m_transport->getHTTPVersion() == "1.1" &&
  334. m_transport->getMethod() != Transport::Method::HEAD))) {
  335. StringBuffer &oss = m_buffers.front()->oss;
  336. if (!oss.empty()) {
  337. if (m_transport) {
  338. m_transport->sendRaw((void*)oss.data(), oss.size(), 200, false, true);
  339. } else {
  340. writeStdout(oss.data(), oss.size());
  341. fflush(stdout);
  342. }
  343. oss.clear();
  344. }
  345. }
  346. }
  347. void ExecutionContext::resetCurrentBuffer() {
  348. if (m_buffers.empty()) {
  349. m_out = nullptr;
  350. } else {
  351. m_out = &m_buffers.back()->oss;
  352. }
  353. }
  354. ///////////////////////////////////////////////////////////////////////////////
  355. // program executions
  356. void ExecutionContext::registerShutdownFunction(const Variant& function,
  357. Array arguments,
  358. ShutdownType type) {
  359. Array callback = make_map_array(s_name, function, s_args, arguments);
  360. Variant& funcs = m_shutdowns.lvalAt(type);
  361. forceToArray(funcs).append(callback);
  362. }
  363. Variant ExecutionContext::popShutdownFunction(ShutdownType type) {
  364. Variant& funcs = m_shutdowns.lvalAt(type);
  365. if (!funcs.isArray()) {
  366. return uninit_null();
  367. }
  368. return funcs.toArrRef().pop();
  369. }
  370. Variant ExecutionContext::pushUserErrorHandler(const Variant& function,
  371. int error_types) {
  372. Variant ret;
  373. if (!m_userErrorHandlers.empty()) {
  374. ret = m_userErrorHandlers.back().first;
  375. }
  376. m_userErrorHandlers.push_back(std::pair<Variant,int>(function, error_types));
  377. return ret;
  378. }
  379. Variant ExecutionContext::pushUserExceptionHandler(const Variant& function) {
  380. Variant ret;
  381. if (!m_userExceptionHandlers.empty()) {
  382. ret = m_userExceptionHandlers.back();
  383. }
  384. m_userExceptionHandlers.push_back(function);
  385. return ret;
  386. }
  387. void ExecutionContext::popUserErrorHandler() {
  388. if (!m_userErrorHandlers.empty()) {
  389. m_userErrorHandlers.pop_back();
  390. }
  391. }
  392. void ExecutionContext::popUserExceptionHandler() {
  393. if (!m_userExceptionHandlers.empty()) {
  394. m_userExceptionHandlers.pop_back();
  395. }
  396. }
  397. void ExecutionContext::registerRequestEventHandler
  398. (RequestEventHandler *handler) {
  399. assert(handler);
  400. if (m_requestEventHandlerSet.find(handler) ==
  401. m_requestEventHandlerSet.end()) {
  402. m_requestEventHandlerSet.insert(handler);
  403. m_requestEventHandlers.push_back(handler);
  404. } else {
  405. assert(false);
  406. }
  407. }
  408. static bool requestEventHandlerPriorityComp(RequestEventHandler *a,
  409. RequestEventHandler *b) {
  410. return a->priority() < b->priority();
  411. }
  412. void ExecutionContext::onRequestShutdown() {
  413. // Sort handlers by priority so that lower priority values get shutdown
  414. // first
  415. sort(m_requestEventHandlers.begin(), m_requestEventHandlers.end(),
  416. requestEventHandlerPriorityComp);
  417. for (unsigned int i = 0; i < m_requestEventHandlers.size(); i++) {
  418. RequestEventHandler *handler = m_requestEventHandlers[i];
  419. assert(handler->getInited());
  420. if (handler->getInited()) {
  421. handler->requestShutdown();
  422. handler->setInited(false);
  423. }
  424. }
  425. m_requestEventHandlers.clear();
  426. m_requestEventHandlerSet.clear();
  427. }
  428. void ExecutionContext::executeFunctions(const Array& funcs) {
  429. ThreadInfo::s_threadInfo->m_reqInjectionData.resetTimer(
  430. RuntimeOption::PspTimeoutSeconds);
  431. for (ArrayIter iter(funcs); iter; ++iter) {
  432. Array callback = iter.second().toArray();
  433. vm_call_user_func(callback[s_name], callback[s_args].toArray());
  434. }
  435. }
  436. void ExecutionContext::onShutdownPreSend() {
  437. // in case obStart was called without obFlush
  438. SCOPE_EXIT { obFlushAll(); };
  439. if (!m_shutdowns.isNull() && m_shutdowns.exists(ShutDown)) {
  440. SCOPE_EXIT { m_shutdowns.remove(ShutDown); };
  441. executeFunctions(m_shutdowns[ShutDown].toArray());
  442. }
  443. }
  444. extern void ext_session_request_shutdown();
  445. void ExecutionContext::onShutdownPostSend() {
  446. ServerStats::SetThreadMode(ServerStats::ThreadMode::PostProcessing);
  447. try {
  448. try {
  449. ServerStatsHelper ssh("psp", ServerStatsHelper::TRACK_HWINST);
  450. if (!m_shutdowns.isNull()) {
  451. if (m_shutdowns.exists(PostSend)) {
  452. SCOPE_EXIT { m_shutdowns.remove(PostSend); };
  453. executeFunctions(m_shutdowns[PostSend].toArray());
  454. }
  455. if (m_shutdowns.exists(CleanUp)) {
  456. SCOPE_EXIT { m_shutdowns.remove(CleanUp); };
  457. executeFunctions(m_shutdowns[CleanUp].toArray());
  458. }
  459. }
  460. } catch (const ExitException &e) {
  461. // do nothing
  462. } catch (const Exception &e) {
  463. onFatalError(e);
  464. } catch (const Object &e) {
  465. onUnhandledException(e);
  466. }
  467. } catch (...) {
  468. Logger::Error("unknown exception was thrown from psp");
  469. }
  470. /*
  471. * This has to happen before requestEventHandler shutdown hooks,
  472. * because it can run user code which may need to access other
  473. * RequestLocal objects (such as the stream registry).
  474. */
  475. ext_session_request_shutdown();
  476. ServerStats::SetThreadMode(ServerStats::ThreadMode::Idling);
  477. }
  478. ///////////////////////////////////////////////////////////////////////////////
  479. // error handling
  480. bool ExecutionContext::errorNeedsHandling(int errnum,
  481. bool callUserHandler,
  482. ErrorThrowMode mode) {
  483. if (m_throwAllErrors) {
  484. throw errnum;
  485. }
  486. if (mode != ErrorThrowMode::Never || errorNeedsLogging(errnum)) {
  487. return true;
  488. }
  489. if (callUserHandler) {
  490. if (!m_userErrorHandlers.empty() &&
  491. (m_userErrorHandlers.back().second & errnum) != 0) {
  492. return true;
  493. }
  494. }
  495. return false;
  496. }
  497. bool ExecutionContext::errorNeedsLogging(int errnum) {
  498. auto level = ThreadInfo::s_threadInfo.getNoCheck()->
  499. m_reqInjectionData.getErrorReportingLevel();
  500. return RuntimeOption::NoSilencer || (level & errnum) != 0;
  501. }
  502. class ErrorStateHelper {
  503. public:
  504. ErrorStateHelper(ExecutionContext *context,
  505. ExecutionContext::ErrorState state) {
  506. m_context = context;
  507. m_originalState = m_context->getErrorState();
  508. m_context->setErrorState(state);
  509. }
  510. ~ErrorStateHelper() {
  511. m_context->setErrorState(m_originalState);
  512. }
  513. private:
  514. ExecutionContext *m_context;
  515. ExecutionContext::ErrorState m_originalState;
  516. };
  517. const StaticString
  518. s_file("file"),
  519. s_line("line");
  520. void ExecutionContext::handleError(const std::string& msg,
  521. int errnum,
  522. bool callUserHandler,
  523. ErrorThrowMode mode,
  524. const std::string& prefix,
  525. bool skipFrame /* = false */) {
  526. SYNC_VM_REGS_SCOPED();
  527. auto newErrorState = ErrorState::ErrorRaised;
  528. switch (getErrorState()) {
  529. case ErrorState::ErrorRaised:
  530. case ErrorState::ErrorRaisedByUserHandler:
  531. return;
  532. case ErrorState::ExecutingUserHandler:
  533. newErrorState = ErrorState::ErrorRaisedByUserHandler;
  534. break;
  535. default:
  536. break;
  537. }
  538. ErrorStateHelper esh(this, newErrorState);
  539. auto const ee = skipFrame ?
  540. ExtendedException(ExtendedException::SkipFrame::skipFrame, msg) :
  541. ExtendedException(msg);
  542. recordLastError(ee, errnum);
  543. bool handled = false;
  544. if (callUserHandler) {
  545. handled = callUserErrorHandler(ee, errnum, false);
  546. }
  547. if (mode == ErrorThrowMode::Always ||
  548. (mode == ErrorThrowMode::IfUnhandled && !handled)) {
  549. DEBUGGER_ATTACHED_ONLY(phpDebuggerErrorHook(msg));
  550. auto exn = FatalErrorException(msg, ee.getBackTrace());
  551. exn.setSilent(!errorNeedsLogging(errnum));
  552. throw exn;
  553. }
  554. if (!handled && errorNeedsLogging(errnum)) {
  555. DEBUGGER_ATTACHED_ONLY(phpDebuggerErrorHook(ee.getMessage()));
  556. String file = empty_string;
  557. int line = 0;
  558. if (RuntimeOption::InjectedStackTrace) {
  559. Array bt = ee.getBackTrace();
  560. if (!bt.empty()) {
  561. Array top = bt.rvalAt(0).toArray();
  562. if (top.exists(s_file)) file = top.rvalAt(s_file).toString();
  563. if (top.exists(s_line)) line = top.rvalAt(s_line).toInt64();
  564. }
  565. }
  566. Logger::Log(Logger::LogError, prefix.c_str(), ee, file.c_str(), line);
  567. }
  568. }
  569. bool ExecutionContext::callUserErrorHandler(const Exception &e, int errnum,
  570. bool swallowExceptions) {
  571. switch (getErrorState()) {
  572. case ErrorState::ExecutingUserHandler:
  573. case ErrorState::ErrorRaisedByUserHandler:
  574. return false;
  575. default:
  576. break;
  577. }
  578. if (!m_userErrorHandlers.empty() &&
  579. (m_userErrorHandlers.back().second & errnum) != 0) {
  580. int errline = 0;
  581. String errfile;
  582. Array backtrace;
  583. if (auto const ee = dynamic_cast<const ExtendedException*>(&e)) {
  584. Array arr = ee->getBackTrace();
  585. if (!arr.isNull()) {
  586. backtrace = arr;
  587. Array top = backtrace.rvalAt(0).toArray();
  588. if (!top.isNull()) {
  589. errfile = top.rvalAt(s_file);
  590. errline = top.rvalAt(s_line).toInt64();
  591. }
  592. }
  593. }
  594. try {
  595. ErrorStateHelper esh(this, ErrorState::ExecutingUserHandler);
  596. Array dummyContext = Array::Create();
  597. if (!same(vm_call_user_func
  598. (m_userErrorHandlers.back().first,
  599. make_packed_array(errnum, String(e.getMessage()), errfile,
  600. errline, dummyContext, backtrace)),
  601. false)) {
  602. return true;
  603. }
  604. } catch (...) {
  605. if (!swallowExceptions) throw;
  606. }
  607. }
  608. return false;
  609. }
  610. bool ExecutionContext::onFatalError(const Exception &e) {
  611. int errnum = static_cast<int>(ErrorConstants::ErrorModes::FATAL_ERROR);
  612. recordLastError(e, errnum);
  613. String file = empty_string;
  614. int line = 0;
  615. bool silenced = false;
  616. if (RuntimeOption::InjectedStackTrace) {
  617. if (auto const ee = dynamic_cast<const ExtendedException *>(&e)) {
  618. silenced = ee->isSilent();
  619. Array bt = ee->getBackTrace();
  620. if (!bt.empty()) {
  621. Array top = bt.rvalAt(0).toArray();
  622. if (top.exists(s_file)) file = top.rvalAt(s_file).toString();
  623. if (top.exists(s_line)) line = top.rvalAt(s_line).toInt32();
  624. }
  625. }
  626. }
  627. // need to silence even with the AlwaysLogUnhandledExceptions flag set
  628. if (!silenced && RuntimeOption::AlwaysLogUnhandledExceptions) {
  629. Logger::Log(Logger::LogError, "\nFatal error: ", e,
  630. file.c_str(), line);
  631. }
  632. bool handled = false;
  633. if (RuntimeOption::CallUserHandlerOnFatals) {
  634. handled = callUserErrorHandler(e, errnum, true);
  635. }
  636. if (!handled && !silenced && !RuntimeOption::AlwaysLogUnhandledExceptions) {
  637. Logger::Log(Logger::LogError, "\nFatal error: ", e,
  638. file.c_str(), line);
  639. }
  640. return handled;
  641. }
  642. bool ExecutionContext::onUnhandledException(Object e) {
  643. String err = e.toString();
  644. if (RuntimeOption::AlwaysLogUnhandledExceptions) {
  645. Logger::Error("\nFatal error: Uncaught %s", err.data());
  646. }
  647. if (e.instanceof(SystemLib::s_ExceptionClass)) {
  648. // user thrown exception
  649. if (!m_userExceptionHandlers.empty()) {
  650. if (!same(vm_call_user_func
  651. (m_userExceptionHandlers.back(),
  652. make_packed_array(e)),
  653. false)) {
  654. return true;
  655. }
  656. }
  657. } else {
  658. assert(false);
  659. }
  660. m_lastError = err;
  661. if (!RuntimeOption::AlwaysLogUnhandledExceptions) {
  662. Logger::Error("\nFatal error: Uncaught %s", err.data());
  663. }
  664. return false;
  665. }
  666. ///////////////////////////////////////////////////////////////////////////////
  667. void ExecutionContext::debuggerInfo(
  668. std::vector<std::pair<const char*,std::string>>& info) {
  669. int64_t newInt = convert_bytes_to_long(IniSetting::Get("memory_limit"));
  670. if (newInt <= 0) {
  671. newInt = INT64_MAX;
  672. }
  673. if (newInt == INT64_MAX) {
  674. info.emplace_back("Max Memory", "(unlimited)");
  675. } else {
  676. info.emplace_back("Max Memory", IDebuggable::FormatSize(newInt));
  677. }
  678. info.emplace_back("Max Time",
  679. IDebuggable::FormatTime(ThreadInfo::s_threadInfo.getNoCheck()->
  680. m_reqInjectionData.getTimeout() * 1000));
  681. }
  682. ///////////////////////////////////////////////////////////////////////////////
  683. void ExecutionContext::setenv(const String& name, const String& value) {
  684. m_envs.set(name, value);
  685. }
  686. String ExecutionContext::getenv(const String& name) const {
  687. if (m_envs.exists(name)) {
  688. return m_envs[name].toString();
  689. }
  690. char *value = ::getenv(name.data());
  691. if (value) {
  692. return String(value, CopyString);
  693. }
  694. if (RuntimeOption::EnvVariables.find(name.c_str()) != RuntimeOption::EnvVariables.end()) {
  695. return String(RuntimeOption::EnvVariables[name.c_str()].data(), CopyString);
  696. }
  697. return String();
  698. }
  699. //////////////////////////////////////////////////////////////////////
  700. }