Variant ThisExpression::set(VariableEnvironment &env, CVarRef val) const { throw FatalErrorException("Cannot re-assign $this"); }
CVarRef ArrayData::endRef() { if (size_t(m_pos) < size_t(size())) { return getValueRef(size() - 1); } throw FatalErrorException("invalid ArrayData::m_pos"); }
void ArrayData::uasort(CVarRef cmp_function) { throw FatalErrorException("Unimplemented ArrayData::uasort"); }
OutputFile::OutputFile(const String& filename): File(true, s_php, s_output) { if (filename != s_php_output) { throw FatalErrorException("not a php://output file "); } m_isLocal = true; }
ArrayData *ArrayData::nonSmartCopy() const { throw FatalErrorException("nonSmartCopy not implemented."); }
CVarRef ArrayData::endRef() { if (m_pos != invalid_index) { return getValueRef(iter_end()); } throw FatalErrorException("invalid ArrayData::m_pos"); }
void ArrayData::ZSetStr(ArrayData* ad, StringData* k, RefData* v) { throw FatalErrorException("Unimplemented ArrayData::ZSetStr"); }
ObjectData *FrameInjectionFunction::getThisForArrow() { if (ObjectData *obj = getThis()) { return obj; } throw FatalErrorException("Using $this when not in object context"); }
ObjectData *FrameInjectionObjectMethod::getThisForArrow() { if (m_object->o_getId()) { return m_object; } throw FatalErrorException("Using $this when not in object context"); }
int64 MemFile::writeImpl(const char *buffer, int64 length) { throw FatalErrorException((string("cannot write a mem stream: ") + m_name).c_str()); }
bool MemFile::flush() { throw FatalErrorException((string("cannot flush a mem stream: ") + m_name).c_str()); }
void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) { assert(wait_handle); assert(wait_handle->getContext() == this); auto session = AsioSession::Get(); auto ete_queue = session->getExternalThreadEventQueue(); if (!session->hasAbruptInterruptException()) { session->initAbruptInterruptException(); } while (!wait_handle->isFinished()) { // Run queue of ready async functions once. if (!m_runnableQueue.empty()) { auto current = m_runnableQueue.back(); m_runnableQueue.pop_back(); current->resume(); continue; } // Process all sleep handles that have completed their sleep. if (session->processSleepEvents()) { continue; } // Process all external thread events that have completed their operation. // Queue may contain received unprocessed events from failed runUntil(). if (UNLIKELY(ete_queue->hasReceived()) || ete_queue->tryReceiveSome()) { ete_queue->processAllReceived(); continue; } // Run default priority queue once. if (runSingle(m_priorityQueueDefault)) { continue; } // Wait for pending external thread events... if (!m_externalThreadEvents.empty()) { // ...but only until the next sleeper (from any context) finishes. auto waketime = session->sleepWakeTime(); // Wait if necessary. if (LIKELY(!ete_queue->hasReceived())) { onIOWaitEnter(session); ete_queue->receiveSomeUntil(waketime); onIOWaitExit(session); } if (ete_queue->hasReceived()) { // Either we didn't have to wait, or we waited but no sleeper timed us // out, so just handle the ETEs. ete_queue->processAllReceived(); } else { // No received events means the next-to-wake sleeper timed us out. session->processSleepEvents(); } continue; } // If we're here, then the only things left are sleepers. Wait for one to // be ready (in any context). if (!m_sleepEvents.empty()) { onIOWaitEnter(session); std::this_thread::sleep_until(session->sleepWakeTime()); onIOWaitExit(session); session->processSleepEvents(); continue; } // Run no-pending-io priority queue once. if (runSingle(m_priorityQueueNoPendingIO)) { continue; } // What? The wait handle did not finish? We know it is part of the current // context and since there is nothing else to run, it cannot be in RUNNING // or SCHEDULED state. So it must be BLOCKED on something. Apparently, the // same logic can be used recursively on the something, so there is an // infinite chain of blocked wait handles. But our memory is not infinite. // What could it possibly mean? I think we are in a deep sh^H^Hcycle. // But we can't, the cycles are detected and avoided at blockOn() time. // So, looks like it's not cycle, but the word I started typing first. assert(false); throw FatalErrorException( "Invariant violation: queues are empty, but wait handle did not finish"); } }
void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) { assert(!m_current); assert(wait_handle); assert(wait_handle->getContext() == this); auto session = AsioSession::Get(); uint8_t check_ete_counter = 0; while (!wait_handle->isFinished()) { // process ready external thread events once per 256 other events // (when 8-bit check_ete_counter overflows) if (!++check_ete_counter) { auto ete_wh = session->getReadyExternalThreadEvents(); while (ete_wh) { auto next_wh = ete_wh->getNextToProcess(); ete_wh->process(); ete_wh = next_wh; } } // run queue of ready continuations once if (!m_runnableQueue.empty()) { auto current = m_runnableQueue.front(); m_runnableQueue.pop(); m_current = current; m_current->run(); m_current = nullptr; decRefObj(current); continue; } // run default priority queue once if (runSingle(m_priorityQueueDefault)) { continue; } // pending external thread events? wait for at least one to become ready if (!m_externalThreadEvents.empty()) { // all your wait time are belong to us auto ete_wh = session->waitForExternalThreadEvents(); while (ete_wh) { auto next_wh = ete_wh->getNextToProcess(); ete_wh->process(); ete_wh = next_wh; } continue; } // run no-pending-io priority queue once if (runSingle(m_priorityQueueNoPendingIO)) { continue; } // What? The wait handle did not finish? We know it is part of the current // context and since there is nothing else to run, it cannot be in RUNNING // or SCHEDULED state. So it must be BLOCKED on something. Apparently, the // same logic can be used recursively on the something, so there is an // infinite chain of blocked wait handles. But our memory is not infinite. // What could it possibly mean? I think we are in a deep sh^H^Hcycle. // But we can't, the cycles are detected and avoided at blockOn() time. // So, looks like it's not cycle, but the word I started typing first. assert(false); throw FatalErrorException( "Invariant violation: queues are empty, but wait handle did not finish"); } }
bool FunctionCallExpression::exist(VariableEnvironment &env, int op) const { throw FatalErrorException(0, "Cannot call %s on a function return value", op == T_ISSET ? "isset" : "empty"); }
CVarRef NameValueTableWrapper::currentRef() { if (m_pos != ArrayData::invalid_index) { return getValueRef(m_pos); } throw FatalErrorException("invalid ArrayData::m_pos"); }
bool TempFile::open(const String& filename, const String& mode) { throw FatalErrorException((std::string("cannot open a temp file ") + m_name).c_str()); }
void c_ContinuationWaitHandle::run() { // may happen if scheduled in multiple contexts if (getState() != STATE_SCHEDULED) { return; } try { setState(STATE_RUNNING); do { // iterate continuation if (m_child.isNull()) { // first iteration or null dependency m_continuation->call_next(); } else if (m_child->isSucceeded()) { // child succeeded, pass the result to the continuation m_continuation->call_send(m_child->getResult()); } else if (m_child->isFailed()) { // child failed, raise the exception inside continuation m_continuation->call_raise(m_child->getException()); } else { throw FatalErrorException( "Invariant violation: child neither succeeded nor failed"); } // continuation finished, retrieve result from its m_value if (m_continuation->m_done) { markAsSucceeded(m_continuation->m_value.asTypedValue()); return; } // set up dependency TypedValue* value = m_continuation->m_value.asTypedValue(); if (IS_NULL_TYPE(value->m_type)) { // null dependency m_child = nullptr; } else { c_WaitHandle* child = c_WaitHandle::fromTypedValue(value); if (UNLIKELY(!child)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected yield argument to be an instance of WaitHandle")); throw e; } AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnContinuationYieldCallback())) { session->onContinuationYield(this, child); } m_child = child; } } while (m_child.isNull() || m_child->isFinished()); // we are blocked on m_child so it must be WaitableWaitHandle assert(dynamic_cast<c_WaitableWaitHandle*>(m_child.get())); blockOn(static_cast<c_WaitableWaitHandle*>(m_child.get())); } catch (const Object& exception) { // process exception thrown by generator or blockOn cycle detection markAsFailed(exception); } }
Variant f_func_get_arg(int arg_num) { throw FatalErrorException("bad HPHP code generation"); }
void ArrayData::ZSetInt(ArrayData* ad, int64_t k, RefData* v) { throw FatalErrorException("Unimplemented ArrayData::ZSetInt"); }
Array f_func_get_args() { throw FatalErrorException("bad HPHP code generation"); }
void ArrayData::ZAppend(ArrayData* ad, RefData* v) { throw FatalErrorException("Unimplemented ArrayData::ZAppend"); }
void Expression::byteCodeRefval(ByteCodeProgram &code) const { throw FatalErrorException("Cannot compile %s:%d", m_loc.file, m_loc.line1); }
bool OutputFile::open(const String& filename, const String& mode) { throw FatalErrorException("cannot open a php://output file "); }
void StringData::append(const char *s, int len) { ASSERT(!isStatic()); // never mess around with static strings! if (len == 0) return; if (UNLIKELY(uint32_t(len) > MaxSize)) { throw InvalidArgumentException("len>=2^30", len); } if (UNLIKELY(len + m_len > MaxSize)) { throw FatalErrorException(0, "String length exceeded 2^30 - 1: %u", len + m_len); } int newlen; // TODO: t1122987: in any of the cases below where we need a bigger buffer, // we can probably assume we're in a concat-loop and pick a good buffer // size to avoid O(N^2) copying cost. if (isShared() || isLiteral()) { // buffer is immutable, don't modify it. // We are mutating, so we don't need to repropagate our own taint StringSlice r = slice(); char* newdata = string_concat(r.ptr, r.len, s, len, newlen); if (isShared()) m_big.shared->decRef(); m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } else if (rawdata() == s) { // appending ourself to ourself, be conservative. // We are mutating, so we don't need to repropagate our own taint StringSlice r = slice(); char *newdata = string_concat(r.ptr, r.len, s, len, newlen); releaseData(); m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } else if (isSmall()) { // we're currently small but might not be after append. // We are mutating, so we don't need to repropagate our own taint int oldlen = m_len; newlen = oldlen + len; if (unsigned(newlen) <= MaxSmallSize) { // win. memcpy(&m_small[oldlen], s, len); m_small[newlen] = 0; m_small[MaxSmallSize] = 0; m_len = newlen; m_data = m_small; m_hash = 0; } else { // small->big string transition. char *newdata = string_concat(m_small, oldlen, s, len, newlen); m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } } else { // generic "big string concat" path. realloc buffer. int oldlen = m_len; char* oldp = m_data; ASSERT((oldp > s && oldp - s > len) || (oldp < s && s - oldp > oldlen)); // no overlapping newlen = oldlen + len; char* newdata = (char*) realloc(oldp, newlen + 1); memcpy(newdata + oldlen, s, len); newdata[newlen] = 0; m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } ASSERT(uint32_t(newlen) <= MaxSize); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, rawdata()); ASSERT(checkSane()); }
ArrayData *ArrayData::lvalPtr(StringData* k, Variant *&ret, bool copy, bool create) { throw FatalErrorException("Unimplemented ArrayData::lvalPtr"); }
ArrayData* GlobalsArray::CopyWithStrongIterators(const ArrayData* ad) { throw FatalErrorException( "Unimplemented ArrayData::copyWithStrongIterators"); }
void ArrayData::asort(int sort_flags, bool ascending) { throw FatalErrorException("Unimplemented ArrayData::asort"); }
ArrayData* GlobalsArray::CopyStatic(const ArrayData*) { throw FatalErrorException("GlobalsArray::copyStatic " "not implemented."); }
ArrayData* ArrayData::copyWithStrongIterators() const { throw FatalErrorException("Unimplemented ArrayData::copyWithStrongIterators"); }
void HttpRequestHandler::handleRequest(Transport *transport) { ExecutionProfiler ep(ThreadInfo::RuntimeFunctions); Logger::OnNewRequest(); GetAccessLog().onNewRequest(); transport->enableCompression(); ServerStatsHelper ssh("all", true); Logger::Verbose("receiving %s", transport->getCommand().c_str()); // will clear all extra logging when this function goes out of scope StackTraceNoHeap::ExtraLoggingClearer clearer; StackTraceNoHeap::AddExtraLogging("URL", transport->getUrl()); // resolve virtual host const VirtualHost *vhost = HttpProtocol::GetVirtualHost(transport); ASSERT(vhost); if (vhost->disabled() || vhost->isBlocking(transport->getCommand(), transport->getRemoteHost())) { transport->sendString("Not Found", 404); return; } ServerStats::StartRequest(transport->getCommand().c_str(), transport->getRemoteHost(), vhost->getName().c_str()); // resolve source root string host = transport->getHeader("Host"); SourceRootInfo sourceRootInfo(host.c_str()); if (sourceRootInfo.error()) { sourceRootInfo.handleError(transport); return; } // request URI string pathTranslation = m_pathTranslation ? vhost->getPathTranslation().c_str() : ""; RequestURI reqURI(vhost, transport, sourceRootInfo.path(), pathTranslation); if (reqURI.done()) { return; // already handled with redirection or 404 } string path = reqURI.path().data(); string absPath = reqURI.absolutePath().data(); // determine whether we should compress response bool compressed = transport->decideCompression(); const char *data; int len; size_t pos = path.rfind('.'); const char *ext = (pos != string::npos) && path.find('/', pos) == string::npos // no extention in ./foo or ../bar ? (path.c_str() + pos + 1) : NULL; bool cachableDynamicContent = (!RuntimeOption::StaticFileGenerators.empty() && RuntimeOption::StaticFileGenerators.find(path) != RuntimeOption::StaticFileGenerators.end()); // If this is not a php file, check the static and dynamic content caches if (ext && strcasecmp(ext, "php") != 0) { if (RuntimeOption::EnableStaticContentCache) { bool original = compressed; // check against static content cache if (StaticContentCache::TheCache.find(path, data, len, compressed)) { struct stat st; st.st_mtime = 0; String str; // (qigao) not calling stat at this point because the timestamp of // local cache file is not valuable, maybe misleading. This way // the Last-Modified header will not show in response. // stat(RuntimeOption::FileCache.c_str(), &st); if (!original && compressed) { data = gzdecode(data, len); if (data == NULL) { throw FatalErrorException("cannot unzip compressed data"); } compressed = false; str = NEW(StringData)(data, len, AttachString); } sendStaticContent(transport, data, len, st.st_mtime, compressed, path); StaticContentCache::TheFileCache->adviseOutMemory(); ServerStats::LogPage(path, 200); return; } } if (RuntimeOption::EnableStaticContentFromDisk) { String translated = File::TranslatePath(String(absPath)); if (!translated.empty()) { StringBuffer sb(translated.data()); if (sb.valid()) { struct stat st; st.st_mtime = 0; stat(translated.data(), &st); sendStaticContent(transport, sb.data(), sb.size(), st.st_mtime, false, path); ServerStats::LogPage(path, 200); return; } } } // check static contents that were generated by dynamic pages if (cachableDynamicContent) { // check against dynamic content cache ASSERT(transport->getUrl()); string key = path + transport->getUrl(); if (DynamicContentCache::TheCache.find(key, data, len, compressed)) { sendStaticContent(transport, data, len, 0, compressed, path); ServerStats::LogPage(path, 200); return; } } } // proxy any URLs that not specified in ServeURLs if (!RuntimeOption::ProxyOrigin.empty() && ((RuntimeOption::UseServeURLs && RuntimeOption::ServeURLs.find(path) == RuntimeOption::ServeURLs.end()) || (RuntimeOption::UseProxyURLs && (RuntimeOption::ProxyURLs.find(path) != RuntimeOption::ProxyURLs.end() || MatchAnyPattern(path, RuntimeOption::ProxyPatterns) || (abs(rand()) % 100) < RuntimeOption::ProxyPercentage)))) { for (int i = 0; i < RuntimeOption::ProxyRetry; i++) { bool force = (i == RuntimeOption::ProxyRetry - 1); // last one if (handleProxyRequest(transport, force)) break; } return; } // record request for debugging purpose std::string tmpfile = HttpProtocol::RecordRequest(transport); // main body hphp_session_init(); vhost->setRequestTimeoutSeconds(); bool ret = false; try { ret = executePHPRequest(transport, reqURI, sourceRootInfo, cachableDynamicContent); } catch (const Eval::DebuggerException &e) { transport->sendString(e.what(), 200); transport->onSendEnd(); hphp_context_exit(g_context.getNoCheck(), true, true, transport->getUrl()); } catch (...) { Logger::Error("Unhandled exception in HPHP server engine."); } GetAccessLog().log(transport, vhost); hphp_session_exit(); HttpProtocol::ClearRecord(ret, tmpfile); }