String HHVM_FUNCTION(strrev,
                     const String& str) {
  auto len = str.size();

  String ret(len, ReserveString);

  const char* data = str.data();
  char* dest = ret.get()->mutableData();

  for (int i = 0; i < len; ++i) {
    dest[i] = data[len - i - 1];
  }

  ret.setSize(len);
  return ret;
}


static Variant preg_match_impl(const StringData* pattern,
                               const StringData* subject,
                               Variant* subpats, int flags, int start_offset,
                               bool global) {
  PCRECache::Accessor accessor;
  if (!pcre_get_compiled_regex_cache(accessor, pattern)) {
    return preg_return_bad_regex_error(false);
  }
  const pcre_cache_entry* pce = accessor.get();

  const bool hackArrOutput = flags & PREG_FB_HACK_ARRAYS;
  const bool includeNonMatchingCaptures = flags & PREG_FB__PRIVATE__HSL_IMPL;

  pcre_extra extra;
  init_local_extra(&extra, pce->extra);
  if (subpats) {
    *subpats = hackArrOutput ? Array::CreateDict() : Array::CreateDArray();
  }
  int exec_options = 0;

  int subpats_order = global ? PREG_PATTERN_ORDER : 0;
  bool offset_capture = false;
  if (flags) {
    offset_capture = flags & PREG_OFFSET_CAPTURE;

    /*
     * subpats_order is pre-set to pattern mode so we change it only if
     * necessary.
     */
    if (flags & 0xff) {
      subpats_order = flags & 0xff;
    }
    if ((global && (subpats_order < PREG_PATTERN_ORDER ||
                    subpats_order > PREG_SET_ORDER)) ||
        (!global && subpats_order != 0)) {
      raise_warning("Invalid flags specified");
      return preg_return_internal_error(init_null());
    }
  }

  /* Negative offset counts from the end of the string. */
  if (start_offset < 0) {
    start_offset = subject->size() + start_offset;
    if (start_offset < 0) {
      start_offset = 0;
    }
  }

  int size_offsets = 0;
  int* offsets = create_offset_array(pce, size_offsets);
  SmartFreeHelper offsetsFreer(offsets);
  int num_subpats = size_offsets / 3;
  if (offsets == nullptr) {
    return preg_return_internal_error(false);
  }

  const char* const* subpat_names = get_subpat_names(pce);
  if (subpat_names == nullptr) {
    return preg_return_internal_error(false);
  }

  /* Allocate match sets array and initialize the values. */

  /* An array of sets of matches for each subpattern after a global match */
  auto match_sets = hackArrOutput ? Array::CreateDict() : Array::CreateDArray();
  if (global && subpats_order == PREG_PATTERN_ORDER) {
    for (int i = 0; i < num_subpats; i++) {
      match_sets.set(i,
        hackArrOutput ? Array::CreateDict() : Array::CreateDArray());
    }
  }

  int matched = 0;

  int g_notempty = 0; // If the match should not be empty
  const char** stringlist; // Holds list of subpatterns
  int i;
  do {

    int count = 0;
    /*
     * Optimization: If the pattern defines a literal substring,
     * compare the strings directly (i.e. memcmp) instead of performing
     * the full regular expression evaluation.
     * Take the slow path if there are any special compile options.
     */
    if (pce->literal_data && !global) {
      assertx(pce->literal_data->isLiteral());
      /* TODO(t13140878): compare literal against multiple substrings
       * in the preg_match_all (global == true) case. */
      count = pce->literal_data->matches(subject, start_offset, offsets) ? 1
        : PCRE_ERROR_NOMATCH;
    } else {
      /* Execute the regular expression. */
      count = pcre_exec(pce->re, &extra, subject->data(), subject->size(),
                        start_offset,
                        exec_options | g_notempty,
                        offsets, size_offsets);

      /* The string was already proved to be valid UTF-8 */
      exec_options |= PCRE_NO_UTF8_CHECK;
    }
    /* Check for too many substrings condition. */
    if (count == 0) {
      raise_warning("Matched, but too many substrings");
      count = size_offsets / 3;
    }

    /* If something has matched */
    if (count > 0) {
      matched++;

      if (subpats) {
        // Try to get the list of substrings and display a warning if failed.
        if (offsets[1] < offsets[0] ||
            pcre_get_substring_list(subject->data(), offsets, count,
                                    &stringlist) < 0) {
          raise_warning("Get subpatterns list failed");
          return preg_return_internal_error(false);
        }

        if (global) {  /* global pattern matching */
          if (subpats_order == PREG_PATTERN_ORDER) {
            /* For each subpattern, insert it into the appropriate array. */
            for (i = 0; i < count; i++) {
              auto const length = offsets[(i<<1)+1] - offsets[i<<1];
              auto const match = String(stringlist[i], length, CopyString);
              auto const value = offset_capture
                ? Variant(str_offset_pair(match, offsets[i<<1], hackArrOutput))
                : Variant(match);
              auto& arr = asArrRef(match_sets.lval(i));
              assertx(arr->isVectorData());
              arr.set(safe_cast<int64_t>(arr.size()), value);
            }
            /*
             * If the number of captured subpatterns on this run is
             * less than the total possible number, pad the result
             * arrays with empty strings.
             */
            if (count < num_subpats) {
              for (; i < num_subpats; i++) {
                auto& arr = asArrRef(match_sets.lval(i));
                assertx(arr->isVectorData());
                arr.set(safe_cast<int64_t>(arr.size()), empty_string());
              }
            }
          } else {
            auto result_set = hackArrOutput
              ? Array::CreateDict()
              : Array::CreateDArray();

            /* Add all the subpatterns to it */
            for (i = 0; i < count; i++) {
              auto const length = offsets[(i<<1)+1] - offsets[i<<1];
              auto const match = String(stringlist[i], length, CopyString);
              auto const value = offset_capture
                ? Variant(str_offset_pair(match, offsets[i<<1], hackArrOutput))
                : Variant(match);
              if (subpat_names[i]) {
                result_set.set(String(subpat_names[i]), value);
              }
              result_set.set(i, value);
            }
            if (includeNonMatchingCaptures && count < num_subpats) {
              auto const match = empty_string();
              for (; i < num_subpats; i++) {
                auto const value = offset_capture
                  ? Variant(str_offset_pair(match, offsets[i<<1], hackArrOutput))
                  : Variant(match);
                if (subpat_names[i]) {
                  result_set.set(String(subpat_names[i]), value);
                }
                result_set.set(i, value);
              }
            }
            /* And add it to the output array */
            auto& arr = subpats->asArrRef();
            assertx(arr->isVectorData());
            arr.set(safe_cast<int64_t>(arr.size()), std::move(result_set));
          }
        } else {      /* single pattern matching */
          /* For each subpattern, insert it into the subpatterns array. */
          auto& arr = subpats->asArrRef();
          for (i = 0; i < count; i++) {
            auto const length = offsets[(i<<1)+1] - offsets[i<<1];
            auto const match = String(stringlist[i], length, CopyString);
            auto const value = offset_capture
              ? Variant(str_offset_pair(match, offsets[i<<1], hackArrOutput))
              : Variant(match);
            if (subpat_names[i]) {
              arr.set(String(subpat_names[i]), value);
            }
            arr.set(i, value);
          }
          if (includeNonMatchingCaptures && count < num_subpats) {
            auto const match = empty_string();
            for (; i < num_subpats; i++) {
              auto const value = offset_capture
                ? Variant(str_offset_pair(match, offsets[i<<1], hackArrOutput))
                : Variant(match);
              if (subpat_names[i]) {
                arr.set(String(subpat_names[i]), value);
              }
              arr.set(i, value);
            }
          }
        }
        pcre_free((void *) stringlist);
      }
    } else if (count == PCRE_ERROR_NOMATCH) {
      /* If we previously set PCRE_NOTEMPTY after a null match,
         this is not necessarily the end. We need to advance
         the start offset, and continue. Fudge the offset values
         to achieve this, unless we're already at the end of the string. */
      if (g_notempty && start_offset < subject->size()) {
        offsets[0] = start_offset;
        offsets[1] = start_offset + 1;
      } else
        break;
    } else {
      if (pcre_need_log_error(count)) {
        pcre_log_error(__FUNCTION__, __LINE__, count,
                       pattern->data(), pattern->size(),
                       subject->data(), subject->size(),
                       "", 0,
                       flags, start_offset, g_notempty, global);
      }
      return preg_return_pcre_error(count, false);
    }

    /* If we have matched an empty string, mimic what Perl's /g options does.
       This turns out to be rather cunning. First we set PCRE_NOTEMPTY and try
       the match again at the same point. If this fails (picked up above) we
       advance to the next character. */
    g_notempty = (offsets[1] == offsets[0])? PCRE_NOTEMPTY | PCRE_ANCHORED : 0;

    /* Advance to the position right after the last full match */
    start_offset = offsets[1];
  } while (global);

  /* Add the match sets to the output array and clean up */
  if (subpats && global && subpats_order == PREG_PATTERN_ORDER) {
    auto& arr = subpats->asArrRef();
    for (i = 0; i < num_subpats; i++) {
      if (subpat_names[i]) {
        arr.set(String(subpat_names[i]), match_sets[i]);
      }
      arr.set(i, match_sets[i]);
    }
  }
  return preg_return_no_error(std::move(matched));
}

security fixes

https://hhvm.com/blog/2021/02/25/security-update.html


void pcre_handle_exec_error(int pcre_code) {
  int preg_code = 0;
  switch (pcre_code) {
  case PCRE_ERROR_MATCHLIMIT:
    preg_code = PHP_PCRE_BACKTRACK_LIMIT_ERROR;
    break;
  case PCRE_ERROR_RECURSIONLIMIT:
    preg_code = PHP_PCRE_RECURSION_LIMIT_ERROR;
    break;
  case PCRE_ERROR_BADUTF8:
    preg_code = PHP_PCRE_BAD_UTF8_ERROR;
    break;
  case PCRE_ERROR_BADUTF8_OFFSET:
    preg_code = PHP_PCRE_BAD_UTF8_OFFSET_ERROR;
    break;
  default:
    preg_code = PHP_PCRE_INTERNAL_ERROR;
    break;
  }
  *rl_last_error_code = preg_code;
}


static int connect_with_timeout(int fd, struct sockaddr *sa_ptr,
                                size_t sa_size, double timeout,
                                const HostURL &hosturl,
                                std::string &errstr, int &errnum) {
  if (timeout <= 0) {
    int retval = connect(fd, sa_ptr, sa_size);
    if (retval < 0) {
      errstr = "unable to connect to " + hosturl.getHostURL();
      errnum = errno;
    }
    return retval;
  }

  // set non-blocking so we can do timeouts
  long arg = fcntl(fd, F_GETFL, nullptr);
  fcntl(fd, F_SETFL, arg | O_NONBLOCK);

  int retval = connect(fd, sa_ptr, sa_size);
  if (retval < 0) {
    if (errno == EINPROGRESS) {
      struct pollfd fds[1];
      fds[0].fd = fd;
      fds[0].events = POLLOUT;
      if (poll(fds, 1, (int)(timeout * 1000))) {
        int valopt;
        socklen_t lon = sizeof(int);
        getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon);
        if (valopt) {
          errstr = "failed to connect to " + hosturl.getHostURL();
          errnum = valopt;
        }
        retval = valopt ? -1 : 0;
      } else {
        errstr = "timed out after ";
        errstr += folly::to<std::string>(timeout);
        errstr += " seconds when connecting to " + hosturl.getHostURL();
        errnum = ETIMEDOUT;
        retval = -1;
      }
    } else {
      errstr = "unable to connect to " + hosturl.getHostURL();
      errnum = errno;
    }
  }

  // set to blocking mode
  arg = fcntl(fd, F_GETFL, nullptr);
  fcntl(fd, F_SETFL, arg & ~O_NONBLOCK);

  return retval;
}

#define PHP_NORMAL_READ 0x0001

#define PHP_BINARY_READ 0x0002


  void beginFrame(const char *symbol) override {
    doTrace(symbol, false);
  }

#define HP_STACK_DELIM        "==>"

#define HP_STACK_DELIM_LEN    (sizeof(HP_STACK_DELIM) - 1)


static int php_ifd_get16u(void *Short, int motorola_intel) {
  if (motorola_intel) {
    return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
  } else {
    return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
  }
}

#define IMAGE_TYPE_GIF 1

#define IMAGE_TYPE_JPEG 2

#define IMAGE_TYPE_PNG 4

#define IMAGE_FILTER_NEGATE         0

#define IMAGE_FILTER_GRAYSCALE      1

#define IMAGE_FILTER_COLORIZE       4

#define IMAGE_FILTER_MAX            11

#define IMAGE_FILTER_MAX_ARGS       6

#define IMAGE_TYPE_WBMP 8

#define IMAGE_TYPE_XPM 16

#define IMAGE_FILTER_BRIGHTNESS     2

#define IMAGE_FILTER_CONTRAST       3

#define IMAGE_FILTER_EDGEDETECT     5

#define IMAGE_FILTER_EMBOSS         6

#define IMAGE_FILTER_SELECTIVE_BLUR 8

#define IMAGE_FILTER_SMOOTH         10

#define IMAGE_FILTER_PIXELATE       11

#define IMAGE_FILTER_MEAN_REMOVAL   9

#define IMAGE_FILTER_GAUSSIAN_BLUR  7


TypedValue HHVM_FUNCTION(str_ireplace_with_count,
                         const Variant& search, const Variant& replace,
                         const Variant& subject, int64_t& count) {
  return tvReturn(str_ireplace(search, replace, subject, count));
}

/* No explicit global definitions found. */


static int php_write(void *buf, uint32_t size) {
  g_context->write((const char *)buf, size);
  return size;
}


static void exif_iif_add_tag(image_info_type *image_info, int section_index,
                             char *name, int tag, int format,
                             size_t length, void* value) {
  exif_iif_add_value(image_info, section_index, name, tag, format,
                     (int)length, value, image_info->motorola_intel);
}


  void endFrame(const TypedValue* retval, const char* symbol,
                bool /*endMain*/ = false) override {
    if (m_stack.empty()) {
      fprintf(stderr, "STACK IMBALANCE empty %s\n", symbol);
      return;
    }
    auto f = m_stack.back();
    m_stack.pop_back();
    if (strcmp(f.m_symbol, symbol) != 0) {
      fprintf(stderr, "STACK IMBALANCE %s\n", symbol);
      return;
    }
    auto& memo = m_memos[symbol];
    if (memo.m_ignore) return;
    ++memo.m_count;
    memo.m_ignore = true;
    VMRegAnchor _;
    ActRec *ar = vmfp();
    // Lots of random cases to skip just to keep this simple for
    // now. There's no reason not to do more later.
    if (ar->func()->isCPPBuiltin() || isResumed(ar)) return;
    auto ret = tvAsCVarRef(retval);
    if (ret.isNull()) return;
    if (!(ret.isString() || ret.isObject() || ret.isArray())) return;
    VariableSerializer vs(VariableSerializer::Type::DebuggerSerialize);
    String sdata;
    try {
      sdata = vs.serialize(ret, true);
    } catch (...) {
      fprintf(stderr, "Serialization failure: %s\n", symbol);
      return;
    }
    if (sdata.length() < 3) return;
    if (ar->func()->cls() && ar->hasThis()) {
      memo.m_has_this = true;
      auto& member_memo = memo.m_member_memos[f.m_args.data()];
      ++member_memo.m_count;
      if (member_memo.m_return_value.length() == 0) { // First time
        member_memo.m_return_value = sdata;
        // Intentionally copy the raw pointer value
        member_memo.m_ret_tv = *retval;
        memo.m_ignore = false;
      } else if (member_memo.m_return_value == sdata) { // Same
        memo.m_ignore = false;
        if ((member_memo.m_ret_tv.m_data.num != retval->m_data.num) ||
            (member_memo.m_ret_tv.m_type != retval->m_type)) {
          memo.m_ret_tv_same = false;
        }
      } else {
        memo.m_member_memos.clear(); // Cleanup and ignore
      }
    } else {
      if (memo.m_return_value.length() == 0) { // First time
        memo.m_return_value = sdata;
        // Intentionally copy the raw pointer value
        memo.m_ret_tv = *retval;
        memo.m_ignore = false;
      } else if (memo.m_return_value == sdata) { // Same
        memo.m_ignore = false;
        if ((memo.m_ret_tv.m_data.num != retval->m_data.num) ||
            (memo.m_ret_tv.m_type != retval->m_type)) {
          memo.m_ret_tv_same = false;
        }
      } else {
        memo.m_return_value = ""; // Different, cleanup and ignore
      }
    }
  }


bool HHVM_FUNCTION(imagedashedline,
    const Resource& image,
    int64_t x1, int64_t y1, int64_t x2, int64_t y2, int64_t color) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  gdImageDashedLine(im, x1, y1, x2, y2, color);
  return true;
}


  ~TraceWalker() {
    free(m_arcBuff);
    for (auto& r : m_recursion) delete[] r.first;
  }


Variant HHVM_FUNCTION(socket_accept,
                      const Resource& socket) {
  auto sock = cast<Socket>(socket);
  struct sockaddr sa;
  socklen_t salen = sizeof(sa);
  auto new_sock = req::make<ConcreteSocket>(
    accept(sock->fd(), &sa, &salen), sock->getType());
  if (!new_sock->valid()) {
    SOCKET_ERROR(new_sock, "unable to accept incoming connection", errno);
    return false;
  }
  return Variant(std::move(new_sock));
}


static char * __cvt(double value, int ndigit, int *decpt, int *sign,
                    int fmode, int pad) {
  register char *s = nullptr;
  char *p, *rve, c;
  size_t siz;

  if (ndigit < 0) {
    siz = -ndigit + 1;
  } else {
    siz = ndigit + 1;
  }

  /* __dtoa() doesn't allocate space for 0 so we do it by hand */
  if (value == 0.0) {
    *decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
    *sign = 0;
    if ((rve = s = (char *)malloc(ndigit?siz:2)) == nullptr) {
      return(nullptr);
    }
    *rve++ = '0';
    *rve = '\0';
    if (!ndigit) {
      return(s);
    }
  } else {
    p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
    if (*decpt == 9999) {
      /* Infinity or Nan, convert to inf or nan like printf */
      *decpt = 0;
      c = *p;
      zend_freedtoa(p);
      return strdup(c == 'I' ? "INF" : "NAN");
    }
    /* Make a local copy and adjust rve to be in terms of s */
    if (pad && fmode) {
      siz += *decpt;
    }
    if ((s = (char *)malloc(siz+1)) == nullptr) {
      zend_freedtoa(p);
      return(nullptr);
    }
    (void)string_copy(s, p, siz);
    rve = s + (rve - p);
    zend_freedtoa(p);
  }

  /* Add trailing zeros */
  if (pad) {
    siz -= rve - s;
    while (--siz) {
      *rve++ = '0';
    }
    *rve = '\0';
  }

  return(s);
}

#define STR_TO_DEC(str, num) do {  \
  num = NUM(*str++);               \
  while (isdigit((int)*str)) {     \
    num *= 10;                     \
    num += NUM(*str++);            \
    if (num >= INT_MAX / 10) {     \
      while (isdigit((int)*str++)) \
        continue;                  \
      break;                       \
    }                              \
  }                                \
} while (0)

#define FIX_PRECISION(adjust, precision, s, s_len) do { \
  if (adjust)                                           \
    while (s_len < precision) {                         \
      *--s = '0';                                       \
      s_len++;                                          \
    }                                                   \
} while (0)

#define INT_NULL        ((int *)0)

static const char* s_null = "(null)";


static Variant mcrypt_generic(const Resource& td, const String& data,
                              bool dencrypt) {
  auto pm = get_valid_mcrypt_resource(td);
  if (!pm) {
    return false;
  } else if (!pm->m_init) {
    raise_warning("Operation disallowed prior to mcrypt_generic_init().");
    return false;
  }

  if (data.empty()) {
    raise_warning("An empty string was passed");
    return false;
  }

  String s;
  unsigned char* data_s;
  int block_size, data_size;
  /* Check blocksize */
  if (mcrypt_enc_is_block_mode(pm->m_td) == 1) { /* It's a block algorithm */
    block_size = mcrypt_enc_get_block_size(pm->m_td);
    data_size = (((data.size() - 1) / block_size) + 1) * block_size;
    s = String(data_size, ReserveString);
    data_s = (unsigned char *)s.mutableData();
    memset(data_s, 0, data_size);
    memcpy(data_s, data.data(), data.size());
  } else { /* It's not a block algorithm */
    data_size = data.size();
    s = String(data_size, ReserveString);
    data_s = (unsigned char *)s.mutableData();
    memcpy(data_s, data.data(), data.size());
  }

  if (dencrypt) {
    mdecrypt_generic(pm->m_td, data_s, data_size);
  } else {
    mcrypt_generic(pm->m_td, data_s, data_size);
  }
  s.setSize(data_size);
  return s;
}


static int php_ifd_get32s(void *Long, int motorola_intel) {
  if (motorola_intel) {
    return (((unsigned char *)Long)[0] << 24) |
           (((unsigned char *)Long)[1] << 16) |
           (((unsigned char *)Long)[2] << 8) |
           (((unsigned char *)Long)[3] << 0);
  } else {
    return (((unsigned char *)Long)[3] << 24) |
           (((unsigned char *)Long)[2] << 16) |
           (((unsigned char *)Long)[1] << 8) |
           (((unsigned char *)Long)[0] << 0);
  }
}


  int64_t length() const {
    return m_str ? m_str->size() : 0;
  }

String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

static const int npos = -1;

int find(char ch, int pos = 0, bool caseSensitive = true) const;

int find(const char *s, int pos = 0, bool caseSensitive = true) const;

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(char ch, int pos = 0, bool caseSensitive = true) const;

int rfind(const char *s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator == (const char* v) const = delete;

bool operator != (const char* v) const = delete;

bool operator >= (const char* v) const = delete;

bool operator <= (const char* v) const = delete;

bool operator >  (const char* v) const = delete;

bool operator <  (const char* v) const = delete;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

bool operator == (const Variant& v) const = delete;

bool operator != (const Variant& v) const = delete;

bool operator >= (const Variant& v) const = delete;

bool operator <= (const Variant& v) const = delete;

bool operator >  (const Variant& v) const = delete;

bool operator <  (const Variant& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;


Variant HHVM_FUNCTION(imagecreatefromgif, const String& filename) {
  gdImagePtr im =
    _php_image_create_from(filename, -1, -1, -1, -1,
                           PHP_GDIMG_TYPE_GIF, "GIF",
                           (gdImagePtr(*)())gdImageCreateFromGif,
                           (gdImagePtr(*)())gdImageCreateFromGifCtx);
  if (im == nullptr) {
    return false;
  }
  return Variant(req::make<Image>(im));
}


String HHVM_FUNCTION(strtolower,
                     const String& str) {
  return stringForEachFast(str, tolower);
}


  static void compileTimeAssertions() {
    static_assert(offsetof(StrNR, m_px) == kExpectedMPxOffset, "");
  }

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

static const int npos = -1;

struct StrNR {
private:
  StringData *m_px;

public:
  StrNR() : m_px(nullptr) {}
  explicit StrNR(StringData *sd) : m_px(sd) {}
  explicit StrNR(const StringData *sd) : m_px(const_cast<StringData*>(sd)) {}
  explicit StrNR(const String &s) : m_px(s.get()) {} // XXX
  explicit StrNR(const char*) = delete;

  ~StrNR() {
    if (debug) {
      m_px = reinterpret_cast<StringData*>(0xdeadbeeffaceb004);
    }
  }

  /* implicit */ operator

static uint32_t CreateAll();

static bool s_globalInit;

void init(const char* s, size_t len);

static std::vector<std::tuple<const char*, size_t, StaticString*>>*
    s_registered;


void pcre_reinit() {
  PCRECache::CacheKind kind;
  if (RuntimeOption::EvalPCRECacheType == "static") {
    kind = PCRECache::CacheKind::Static;
  } else if (RuntimeOption::EvalPCRECacheType == "lru") {
    kind = PCRECache::CacheKind::Lru;
  } else if (RuntimeOption::EvalPCRECacheType == "scalable") {
    kind = PCRECache::CacheKind::Scalable;
  } else {
    Logger::Warning("Eval.PCRECacheType should be either static, "
                    "lru or scalable");
    kind = PCRECache::CacheKind::Scalable;
  }
  s_pcreCache.reinit(kind);
}


static size_t exif_convert_any_to_int(void *value, int format,
                                      int motorola_intel) {
  int s_den;
  unsigned u_den;

  switch(format) {
    case TAG_FMT_SBYTE:
      return *(signed char *)value;
    case TAG_FMT_BYTE:
      return *(unsigned char *)value;

    case TAG_FMT_USHORT:
      return php_ifd_get16u(value, motorola_intel);
    case TAG_FMT_ULONG:
      return php_ifd_get32u(value, motorola_intel);

    case TAG_FMT_URATIONAL:
      u_den = php_ifd_get32u(4+(char *)value, motorola_intel);
      if (u_den == 0) {
        return 0;
      } else {
        return php_ifd_get32u(value, motorola_intel) / u_den;
      }

    case TAG_FMT_SRATIONAL:
      s_den = php_ifd_get32s(4+(char *)value, motorola_intel);
      if (s_den == 0) {
        return 0;
      } else {
        return (size_t)((double)php_ifd_get32s(value, motorola_intel) / s_den);
      }

    case TAG_FMT_SSHORT:
      return php_ifd_get16u(value, motorola_intel);
    case TAG_FMT_SLONG:
      return php_ifd_get32s(value, motorola_intel);

    /* Not sure if this is correct (never seen float used in Exif format) */
    case TAG_FMT_SINGLE:
      return (size_t)*(float *)value;
    case TAG_FMT_DOUBLE:
      return (size_t)*(double *)value;
  }
  return 0;
}


String HHVM_FUNCTION(number_format,
                     double number,
                     int decimals /* = 0 */,
                     const Variant& dec_point_in /* = "." */,
                     const Variant& thousands_sep_in /* = "," */) {

  String dec_point(".");
  if (!dec_point_in.isNull()) {
    dec_point = dec_point_in.toString();
  }
  String thousands_sep(",");
  if (!thousands_sep_in.isNull()) {
    thousands_sep = thousands_sep_in.toString();
  }

  return string_number_format(number, decimals, dec_point, thousands_sep);
}


int preg_replace_callback(Variant& result,
                          const Variant& pattern,
                          const Variant& callback,
                          const Variant& subject,
                          int limit /* = -1 */) {
  int64_t count;
  result = preg_replace_impl(pattern, callback, subject,
                             limit, &count, true, false);
  return count;
}


static struct gfxinfo *php_handle_ico(const req::ptr<File>& stream) {
  struct gfxinfo *result = nullptr;
  const unsigned char *s;
  int num_icons = 0;

  String dim = stream->read(2);
  if (dim.length() != 2) {
    return nullptr;
  }

  s = (unsigned char *)dim.c_str();
  num_icons = (((unsigned int)s[1]) << 8) + ((unsigned int)s[0]);

  if (num_icons < 1 || num_icons > 255) {
    return nullptr;
  }

  result = (struct gfxinfo *)IM_CALLOC(1, sizeof(struct gfxinfo));
  CHECK_ALLOC_R(result, (sizeof(struct gfxinfo)), nullptr);

  while (num_icons > 0) {
    dim = stream->read(16);
    if (dim.length() != 16) {
      break;
    }

    s = (unsigned char *)dim.c_str();

    if ((((unsigned int)s[7]) << 8) + ((unsigned int)s[6]) >= result->bits) {
      result->width  = (unsigned int)s[0];
      result->height = (unsigned int)s[1];
      result->bits   = (((unsigned int)s[7]) << 8) + ((unsigned int)s[6]);
    }
    num_icons--;
  }

  return result;
}


gdImagePtr get_valid_image_resource(const Resource& image) {
  auto img_res = dyn_cast_or_null<Image>(image);
  if (!img_res || !img_res->get()) {
    raise_warning("supplied resource is not a valid Image resource");
    return nullptr;
  }
  return img_res->get();
}


Variant HHVM_FUNCTION(imagecreatefromstring, const String& data) {
  gdImagePtr im;
  int imtype;
  char sig[8];

  if (data.length() < 8) {
    raise_warning("Empty string or invalid image");
    return false;
  }
  memcpy(sig, data.c_str(), 8);
  imtype = _php_image_type(sig);
  switch (imtype) {
  case PHP_GDIMG_TYPE_JPG:
#ifdef HAVE_GD_JPG
    im = _php_image_create_from_string(data, "JPEG",
      (gdImagePtr(*)())gdImageCreateFromJpegCtx);
#else
    raise_warning("No JPEG support");
    return false;
#endif
    break;

  case PHP_GDIMG_TYPE_PNG:
#ifdef HAVE_GD_PNG
    im = _php_image_create_from_string(data, "PNG",
      (gdImagePtr(*)())gdImageCreateFromPngCtx);
#else
    raise_warning("No PNG support");
    return false;
#endif
    break;

  case PHP_GDIMG_TYPE_WEBP:
#ifdef HAVE_LIBVPX
    im = _php_image_create_from_string(data, "WEBP",
      (gdImagePtr(*)())gdImageCreateFromWebpCtx);
#else
    raise_warning("No webp support (libvpx is needed)");
    return false;
#endif
    break;

  case PHP_GDIMG_TYPE_GIF:
    im = _php_image_create_from_string(data, "GIF",
      (gdImagePtr(*)())gdImageCreateFromGifCtx);
    break;

  case PHP_GDIMG_TYPE_WBM:
    im = _php_image_create_from_string(data, "WBMP",
      (gdImagePtr(*)())gdImageCreateFromWBMPCtx);
    break;

  case PHP_GDIMG_TYPE_GD2:
    im = _php_image_create_from_string(data, "GD2",
      (gdImagePtr(*)())gdImageCreateFromGd2Ctx);
    break;

  default:
    raise_warning("Data is not in a recognized format");
    return false;
  }

  if (!im) {
    raise_warning("Couldn't create GD Image Stream out of Data");
    return false;
  }
  return Variant(req::make<Image>(im));
}


McryptExtension() : Extension("mcrypt") {}


Variant HHVM_FUNCTION(imagecolorresolvealpha, const Resource& image,
    int64_t red, int64_t green, int64_t blue, int64_t alpha) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  return gdImageColorResolveAlpha(im, red, green, blue, alpha);
}


  void writeStats(Array &ret) override {
    extractStats(ret, m_stats, m_flags, m_MHz);
  }


inline void StringData::invalidateHash() {
  assertx(!isImmutable());
  assertx(!hasMultipleRefs());
  m_hash = 0;
  assertx(checkSane());
}

inline folly::StringPiece

inline folly::MutableStringPiece

struct string_data_hash {
  size_t operator()(const StringData *s) const {
    return s->hash();
  }

struct string_data_same {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->same(s2);
  }

struct string_data_eq_same {
  bool operator()(const StringData* a, const StringData* b) const {
    return a == b || a->same(b);
  }

struct string_data_isame {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->isame(s2);
  }

struct string_data_lt {
  bool operator()(const StringData *s1, const StringData *s2) const {
    int len1 = s1->size();
    int len2 = s2->size();
    if (len1 < len2) {
      return (len1 == 0) || (memcmp(s1->data(), s2->data(), len1) <= 0);
    } else

struct string_data_lti {
  bool operator()(const StringData *s1, const StringData *s2) const {
    return bstrcasecmp(s1->data(), s1->size(), s2->data(), s2->size()) < 0;
  }


php_image_filter_contrast(gdImagePtr im, int arg1 /* = 0 */,
                          int /*arg2*/ /* = 0 */, int /*arg3*/ /* = 0 */,
                          int /*arg4*/ /* = 0 */) {
  int contrast = arg1;
  return gdImageContrast(im, contrast) == 1;
}


bool HHVM_FUNCTION(imagechar, const Resource& image,
    int64_t font, int64_t x, int64_t y,
    const String& c, int64_t color) {
  return php_imagechar(image, font, x, y, c, color, 0);
}


int skipheader (gdIOCtx *ctx) {
  int i;

  do {
    i = (ctx->getC)(ctx);
    if (i < 0) return (-1);
  }
  while (i & 0x80);

  return (0);
}


Variant HHVM_FUNCTION(imagesy, const Resource& image) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  return gdImageSY(im);
}


int string_crc32(const char *p, int len) {
  uint32_t crcinit = 0;
  register int32_t crc = crcinit ^ 0xFFFFFFFF;
  for (; len--; ++p) {
    crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*p)) & 0xFF];
  }
  return crc ^ 0xFFFFFFFF;
}


get_subpat_names(const pcre_cache_entry* pce) {
  char **subpat_names = pce->subpat_names.load(std::memory_order_relaxed);
  if (subpat_names) {
    return subpat_names;
  }

  /*
  * Build a mapping from subpattern numbers to their names. We will always
  * allocate the table, even though there may be no named subpatterns. This
  * avoids somewhat more complicated logic in the inner loops.
  */
  pcre_extra extra;
  init_local_extra(&extra, pce->extra);

  int name_count;

  subpat_names = (char **)calloc(pce->num_subpats, sizeof(char *));
  int rc = pcre_fullinfo(pce->re, &extra, PCRE_INFO_NAMECOUNT, &name_count);
  if (rc < 0) {
    raise_warning("Internal pcre_fullinfo() error %d", rc);
    return nullptr;
  }
  if (name_count > 0) {
    int name_size, ni = 0;
    unsigned short name_idx;
    char* name_table;
    int rc1, rc2;

    rc1 = pcre_fullinfo(pce->re, &extra, PCRE_INFO_NAMETABLE, &name_table);
    rc2 = pcre_fullinfo(pce->re, &extra, PCRE_INFO_NAMEENTRYSIZE, &name_size);
    rc = rc2 ? rc2 : rc1;
    if (rc < 0) {
      raise_warning("Internal pcre_fullinfo() error %d", rc);
      return nullptr;
    }
    // The table returned by PCRE_INFO_NAMETABLE is an array of fixed length
    // strings of size PCRE_INFO_NAMEENTRYSIZE.  The first two bytes are a
    // big-endian uint16_t defining the array index followed by the
    // zero-terminated name string.
    // (See https://www.pcre.org/original/doc/html/pcreapi.html)
    while (ni++ < name_count) {
      name_idx = 0x100 * (unsigned char)name_table[0] +
                 (unsigned char)name_table[1];
      subpat_names[name_idx] = name_table + 2;
      if (is_numeric_string(subpat_names[name_idx],
                            strlen(subpat_names[name_idx]),
                            nullptr, nullptr, 0) != KindOfNull) {
        raise_warning("Numeric named subpatterns are not allowed");
        return nullptr;
      }
      name_table += name_size;
    }
  }
  // Store subpat_names into the cache entry
  char **expected = nullptr;
  if (!pce->subpat_names.compare_exchange_strong(expected, subpat_names)) {
    // Another thread stored subpat_names already. The array created by the
    // other thread is now in expected, return it instead and delete the one
    // we just made.
    free(subpat_names);
    return expected;
  }
  return subpat_names;
}


String HHVM_FUNCTION(implode,
                     const Variant& arg1,
                     const Variant& arg2 /* = uninit_variant */) {
  if (isContainer(arg1)) {
    return StringUtil::Implode(arg1, arg2.toString(), false);
  } else if (arg1.isClsMeth() && RO::EvalIsCompatibleClsMethType) {
    raiseClsMethToVecWarningHelper(__FUNCTION__+2);
    auto const clsMeth = arg1.toClsMethVal();
    return concat3(
      StrNR(clsMeth->getCls()->name()),
      arg2.toString(),
      StrNR(clsMeth->getFunc()->name()));
  } else if (isContainer(arg2)) {
    return StringUtil::Implode(arg2, arg1.toString(), false);
  } else if (arg2.isClsMeth() && RO::EvalIsCompatibleClsMethType) {
    raiseClsMethToVecWarningHelper(__FUNCTION__+2);
    auto const clsMeth = arg2.toClsMethVal();
    return concat3(
      StrNR(clsMeth->getCls()->name()),
      arg1.toString(),
      StrNR(clsMeth->getFunc()->name()));
  } else {
    raise_bad_type_warning("implode() expects a container as "
                             "one of the arguments");
    return String();
  }
}


Variant HHVM_FUNCTION(imagecolorresolve, const Resource& image,
    int64_t red, int64_t green, int64_t blue) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  return gdImageColorResolve(im, red, green, blue);
}


static int exif_discard_imageinfo(image_info_type *ImageInfo) {
  int i;

  if (ImageInfo->UserComment) IM_FREE(ImageInfo->UserComment);
  if (ImageInfo->UserCommentEncoding) {
    IM_FREE(ImageInfo->UserCommentEncoding);
  }
  if (ImageInfo->Copyright) IM_FREE(ImageInfo->Copyright);
  if (ImageInfo->CopyrightPhotographer) {
    IM_FREE(ImageInfo->CopyrightPhotographer);
  }
  if (ImageInfo->CopyrightEditor) IM_FREE(ImageInfo->CopyrightEditor);
  if (ImageInfo->Thumbnail.data) IM_FREE(ImageInfo->Thumbnail.data);
  if (ImageInfo->encode_unicode) IM_FREE(ImageInfo->encode_unicode);
  if (ImageInfo->decode_unicode_be) {
    IM_FREE(ImageInfo->decode_unicode_be);
  }
  if (ImageInfo->decode_unicode_le) {
    IM_FREE(ImageInfo->decode_unicode_le);
  }
  if (ImageInfo->encode_jis) IM_FREE(ImageInfo->encode_jis);
  if (ImageInfo->decode_jis_be) IM_FREE(ImageInfo->decode_jis_be);
  if (ImageInfo->decode_jis_le) IM_FREE(ImageInfo->decode_jis_le);
  if (ImageInfo->make) IM_FREE(ImageInfo->make);
  if (ImageInfo->model) IM_FREE(ImageInfo->model);
  for (i=0; i<ImageInfo->xp_fields.count; i++) {
    if (ImageInfo->xp_fields.list[i].value) {
      IM_FREE(ImageInfo->xp_fields.list[i].value);
    }
  }
  if (ImageInfo->xp_fields.list) IM_FREE(ImageInfo->xp_fields.list);
  for (i=0; i<SECTION_COUNT; i++) {
    exif_iif_free(ImageInfo, i);
  }
  exif_file_sections_free(ImageInfo);
  memset(ImageInfo, 0, sizeof(*ImageInfo));
  return 1;
}


  int64_t size() const {
    return m_str ? m_str->size() : 0;
  }


Variant HHVM_FUNCTION(imagefttext,
    const Resource& image,
    const Variant& size, const Variant& angle,
    int64_t x, int64_t y, int64_t col,
    const String& font_file, const String& text,
    const Array& extrainfo) {
  return php_imagettftext_common(TTFTEXT_DRAW, 1,
    image, size, angle, x, y, col, font_file, text, extrainfo);
}


static int php_skip_variable(const req::ptr<File>& stream) {
  off_t length = (unsigned int)php_read2(stream);

  if (length < 2) {
    return 0;
  }
  length = length - 2;
  stream->seek(length, SEEK_CUR);
  return 1;
}


inline void StringData::checkStack() const {
  assertx(uintptr_t(this) - s_stackLimit >= s_stackSize);
}


Variant HHVM_FUNCTION(socket_server,
                      const String& hostname,
                      int port,
                      Variant& errnum,
                      Variant& errstr) {
  HostURL hosturl(static_cast<const std::string>(hostname), port);
  return socket_server_impl(hosturl,
                            k_STREAM_SERVER_BIND|k_STREAM_SERVER_LISTEN,
                            errnum, errstr);
}


static inline char *php_ecvt(double value, int ndigit, int *decpt, int *sign) {
  return(__cvt(value, ndigit, decpt, sign, 0, 1));
}

#define STR_TO_DEC(str, num) do {  \
  num = NUM(*str++);               \
  while (isdigit((int)*str)) {     \
    num *= 10;                     \
    num += NUM(*str++);            \
    if (num >= INT_MAX / 10) {     \
      while (isdigit((int)*str++)) \
        continue;                  \
      break;                       \
    }                              \
  }                                \
} while (0)

#define INT_NULL        ((int *)0)

static const char* s_null = "(null)";


Variant HHVM_FUNCTION(sscanf, const String& str, const String& format) {
  Variant ret;
  int result;
  result = string_sscanf(str.c_str(), format.c_str(), 0, ret);
  if (SCAN_ERROR_WRONG_PARAM_COUNT == result) return init_null();
  return ret;
}


  static req::ptr<CSRequest> GetRequest(const Variant& var) {
    if (var.isResource()) {
      return dyn_cast_or_null<CSRequest>(var);
    }
    if (var.isString() || var.isObject()) {
      BIO *in = Certificate::ReadData(var);
      if (in == nullptr) return nullptr;

      X509_REQ *csr = PEM_read_bio_X509_REQ(in, nullptr,nullptr,nullptr);
      BIO_free(in);
      if (csr) {
        return req::make<CSRequest>(csr);
      }
    }
    return nullptr;
  }

const int64_t k_OPENSSL_RAW_DATA = 1;

const int64_t k_OPENSSL_ZERO_PADDING = 2;

const int64_t k_OPENSSL_NO_PADDING = 3;

const int64_t k_OPENSSL_PKCS1_OAEP_PADDING = 4;

const int64_t k_OPENSSL_SSLV23_PADDING = 2;

const int64_t k_OPENSSL_PKCS1_PADDING = 1;

static char default_ssl_conf_filename[PATH_MAX];

struct OpenSSLInitializer {
  OpenSSLInitializer() {
    SSL_library_init();
    OpenSSL_add_all_ciphers();
    OpenSSL_add_all_digests();
    OpenSSL_add_all_algorithms();

// CCM ciphers are not added by default, so let's add them!
#if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && \
    OPENSSL_VERSION_NUMBER < 0x100020000
    EVP_add_cipher(EVP_aes_128_ccm());
    EVP_add_cipher(EVP_aes_192_ccm());
    EVP_add_cipher(EVP_aes_256_ccm());
#endif

    ERR_load_ERR_strings();
    ERR_load_crypto_strings();
    ERR_load_EVP_strings();

    /* Determine default SSL configuration file */
    char *config_filename = getenv("OPENSSL_CONF");
    if (config_filename == nullptr) {
      config_filename = getenv("SSLEAY_CONF");
    }

    /* default to 'openssl.cnf' if no environment variable is set */
    if (config_filename == nullptr) {
      snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename),
               "%s/%s", X509_get_default_cert_area(), "openssl.cnf");
    } else {
      always_assert(
        strlen(config_filename) < sizeof(default_ssl_conf_filename));
      strcpy(default_ssl_conf_filename, config_filename);
    }
  }

  ~OpenSSLInitializer() {
    EVP_cleanup();
  }
}

static OpenSSLInitializer s_openssl_initializer;


int64_t MemFile::tell() {
  assertx(m_len != -1);
  return getPosition();
}


String HHVM_FUNCTION(addslashes,
                     const String& str) {
  if (str.empty()) {
    return str;
  }

  return stringForEachBuffered(
    str.size(), str,
    [&](StringBuffer& ret, const char* src, const char* /*end*/) {
      switch (*src) {
        case '\0':
          ret.append('\\');
          ret.append('0');
          break;
        case '\\':
        case '\"':
        case '\'':
          ret.append('\\');
        /* fall through */
        default:
          ret.append(*src);
      }
    });
}


Variant HHVM_FUNCTION(imageaffine,
                      const Resource& image,
                      const Array& affine /* = Array() */,
                      const Array& clip /* = Array() */) {
  gdImagePtr src = get_valid_image_resource(image);
  if (!src) return false;
  gdImagePtr dst = nullptr;
  gdRect rect;
  gdRectPtr pRect = nullptr;
  int nelem = affine.size();
  int i;
  double daffine[6];

  if (nelem != 6) {
    raise_warning("imageaffine(): Affine array must have six elements");
    return false;
  }

  for (i = 0; i < nelem; i++) {
    if (affine[i].isInteger()) {
      daffine[i] = affine[i].toInt64();
    } else if (affine[i].isDouble() || affine[i].isString()) {
      daffine[i] = affine[i].toDouble();
    } else {
      raise_warning("imageaffine(): Invalid type for element %i", i);
      return false;
    }
  }

  if (!clip.empty()) {
    if (clip.exists(s_x)) {
      rect.x = clip[s_x].toInt64();
    } else {
      raise_warning("imageaffine(): Missing x position");
      return false;
    }
    if (clip.exists(s_y)) {
      rect.y = clip[s_y].toInt64();
    } else {
      raise_warning("imageaffine(): Missing y position");
      return false;
    } if (clip.exists(s_width)) {
      rect.width = clip[s_width].toInt64();
    } else {
      raise_warning("imageaffine(): Missing width position");
      return false;
    }
    if (clip.exists(s_height)) {
      rect.height = clip[s_height].toInt64();
    } else {
      raise_warning("imageaffine(): Missing height position");
      return false;
    }
    pRect = ▭
  } else {
    rect.x = -1;
    rect.y = -1;
    rect.width = gdImageSX(src);
    rect.height = gdImageSY(src);
    pRect = nullptr;
  }

  if (gdTransformAffineGetImage(&dst, src, pRect, daffine) != GD_TRUE) {
    return false;
  }
  return Variant(req::make<Image>(dst));
}


inline size_t StringData::estimateCap(size_t size) {
  assertx(size <= MaxSize);
  return MemoryManager::sizeClass(size + kStringOverhead);
}


Variant HHVM_FUNCTION(iptcparse, const String& iptcblock) {
  unsigned int inx = 0, len, tagsfound = 0;
  unsigned char *buffer, recnum, dataset, key[16];
  unsigned int str_len = iptcblock.length();
  Array ret;

  buffer = (unsigned char *)iptcblock.c_str();
  while (inx < str_len) { /* find 1st tag */
    if ((buffer[inx] == 0x1c) &&
        ((buffer[inx+1] == 0x01) || (buffer[inx+1] == 0x02))) {
      break;
    } else {
      inx++;
    }
  }

  while (inx < str_len) {
    if (buffer[ inx++ ] != 0x1c) {
     /* we ran against some data which does not conform to IPTC -
        stop parsing! */
      break;
    }

    if ((inx + 4) >= str_len)
      break;

    dataset = buffer[inx++];
    recnum = buffer[inx++];

    if (buffer[inx] & (unsigned char) 0x80) { /* long tag */
      if (inx + 6 >= str_len) break;

      len = (((long)buffer[inx + 2]) << 24) +
            (((long)buffer[inx + 3]) << 16) +
            (((long)buffer[inx + 4]) <<  8) +
            (((long)buffer[inx + 5]));
      inx += 6;
    } else { /* short tag */
      len = (((unsigned short)buffer[inx])<<8) |
            (unsigned short)buffer[inx+1];
      inx += 2;
    }

    snprintf((char *)key, sizeof(key), "%d#%03d",
             (unsigned int)dataset, (unsigned int)recnum);

    if ((len > str_len) || (inx + len) > str_len) {
      break;
    }

    String skey((const char *)key, CopyString);
    if (!ret.exists(skey)) {
      ret.set(skey, Array::CreateVArray());
    }
    auto const lval = ret.lval(skey);
    forceToArray(lval).append(
      String((const char *)(buffer+inx), len, CopyString));
    inx += len;
    tagsfound++;
  }

  if (!tagsfound) {
    return false;
  }
  return ret;
}


String HHVM_FUNCTION(strip_tags,
                     const String& str,
                     const Variant& allowable_tags /* = "" */) {
  return StringUtil::StripHTMLTags(str, allowable_tags.toString());
}


static Variant php_pcre_replace(const String& pattern, const String& subject,
                                const Variant& replace_var, bool callable,
                                int limit, int* replace_count) {
  PCRECache::Accessor accessor;
  if (!pcre_get_compiled_regex_cache(accessor, pattern.get())) {
    return preg_return_bad_regex_error(init_null());
  }
  const pcre_cache_entry* pce = accessor.get();
  if (pce->preg_options & PREG_REPLACE_EVAL) {
    raise_error("preg_replace(): Support for the /e modifier has been removed, use "
                "preg_replace_callback instead");
  }

  int size_offsets;
  int* offsets = create_offset_array(pce, size_offsets);
  SmartFreeHelper offsetsFreer(offsets);
  if (offsets == nullptr) {
    return preg_return_internal_error(init_null());
  }

  const char* const* subpat_names = get_subpat_names(pce);
  if (subpat_names == nullptr) {
    return preg_return_internal_error(init_null());
  }

  const char* replace = nullptr;
  const char* replace_end = nullptr;
  int replace_len = 0;
  String replace_val;

  if (!callable) {
    replace_val = replace_var.toString();
    replace = replace_val.data();
    replace_len = replace_val.size();
    replace_end = replace + replace_len;
  }

  StringBuffer result(2 * subject.size());

  try {

    /* Initialize */
    const char* match = nullptr;
    int start_offset = 0;
    pcre_extra extra;
    init_local_extra(&extra, pce->extra);

    const char* walk;     // Used to walk the replacement string
    char walk_last;       // Last walked character
    int match_len;        // Length of the current match
    int backref;          // Backreference number
    int g_notempty = 0;   // If the match should not be empty
    int exec_options = 0; // Options passed to pcre_exec
    while (1) {
      /* Execute the regular expression. */
      int count = pcre_exec(pce->re, &extra, subject.data(), subject.size(),
                            start_offset,
                            exec_options | g_notempty,
                            offsets, size_offsets);

      /* The string was already proved to be valid UTF-8 */
      exec_options |= PCRE_NO_UTF8_CHECK;

      /* Check for too many substrings condition. */
      if (count == 0) {
        raise_warning("Matched, but too many substrings");
        count = size_offsets / 3;
      }

      const char* piece = subject.data() + start_offset;
      if (count > 0 && offsets[1] >= offsets[0] &&
          (limit == -1 || limit > 0)) {
        if (replace_count) {
          ++*replace_count;
        }
        /* Set the match location in subject */
        match = subject.data() + offsets[0];

        String callable_result;
        if (callable) {
          /* Use custom function to get replacement string and its length. */
          callable_result = preg_do_repl_func(replace_var, subject, offsets,
                                              subpat_names, count);
        } else { /* do regular substitution */
          walk = replace;
          walk_last = 0;
          while (walk < replace_end) {
            if ('\\' == *walk || '$' == *walk) {
              if (walk_last == '\\') {
                walk++;
                walk_last = 0;
                continue;
              }
              if (preg_get_backref(&walk, &backref)) {
                if (backref < count) {
                  match_len = offsets[(backref<<1)+1] - offsets[backref<<1];
                }
                continue;
              }
            }
            walk++;
            walk_last = walk[-1];
          }
        }

        /* copy the part of the string before the match */
        result.append(piece, match-piece);

        /* copy replacement and backrefs */
        int result_len = result.size();

        if (callable) {
          /* Copy result from custom function to buffer and clean up. */
          result.append(callable_result.data(), callable_result.size());
          result_len += callable_result.size();
        } else { /* do regular backreference copying */
          walk = replace;
          walk_last = 0;
          Array params;
          while (walk < replace_end) {
            if ('\\' == *walk || '$' == *walk) {
              if (walk_last == '\\') {
                result.set(result.size() - 1, *walk++);
                walk_last = 0;
                continue;
              }
              if (preg_get_backref(&walk, &backref)) {
                if (backref < count) {
                  match_len = offsets[(backref<<1)+1] - offsets[backref<<1];
                  result.append(
                    subject.data() + offsets[backref<<1],
                    match_len
                  );
                }
                continue;
              }
            }
            result.append(*walk++);
            walk_last = walk[-1];
          }
        }

        if (limit != -1) {
          limit--;
        }

      } else if (count == PCRE_ERROR_NOMATCH || limit == 0) {
        /* If we previously set PCRE_NOTEMPTY after a null match,
           this is not necessarily the end. We need to advance
           the start offset, and continue. Fudge the offset values
           to achieve this, unless we're already at the end of the string. */
        if (g_notempty != 0 && start_offset < subject.size()) {
          offsets[0] = start_offset;
          offsets[1] = start_offset + 1;
          result.append(piece, 1);
        } else {
          /* stick that last bit of string on our output */
          result.append(piece, subject.size() - start_offset);
          break;
        }
      } else {
        if (pcre_need_log_error(count)) {
          const char* s;
          int size;
          String stemp;
          if (callable) {
            if (replace_var.isObject()) {
              stemp = replace_var.asCObjRef()->getClassName().asString()
                    + "::__invoke";
            } else {
              stemp = replace_var.toString();
            }
            s = stemp.data();
            size = stemp.size();
          } else {
            s = replace_val.data();
            size = replace_val.size();
          }
          pcre_log_error(__FUNCTION__, __LINE__, count,
                         pattern.data(), pattern.size(),
                         subject.data(), subject.size(),
                         s, size,
                         callable, limit, start_offset, g_notempty);
        }
        return preg_return_pcre_error(count, init_null());
      }

      /* If we have matched an empty string, mimic what Perl's /g options does.
         This turns out to be rather cunning. First we set PCRE_NOTEMPTY and try
         the match again at the same point. If this fails (picked up above) we
         advance to the next character. */
      g_notempty = (offsets[1] == offsets[0])? PCRE_NOTEMPTY | PCRE_ANCHORED : 0;

      /* Advance to the next piece. */
      start_offset = offsets[1];
    }

    return preg_return_no_error(result.detach());
  } catch (...) {
    throw;
  }
}


struct string_data_hash {
  size_t operator()(const StringData *s) const {
    return s->hash();
  }

struct string_data_same {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->same(s2);
  }

struct string_data_eq_same {
  bool operator()(const StringData* a, const StringData* b) const {
    return a == b || a->same(b);
  }

struct string_data_isame {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->isame(s2);
  }

struct string_data_lt {
  bool operator()(const StringData *s1, const StringData *s2) const {
    int len1 = s1->size();
    int len2 = s2->size();
    if (len1 < len2) {
      return (len1 == 0) || (memcmp(s1->data(), s2->data(), len1) <= 0);
    } else

struct string_data_lti {
  bool operator()(const StringData *s1, const StringData *s2) const {
    return bstrcasecmp(s1->data(), s1->size(), s2->data(), s2->size()) < 0;
  }


String HHVM_FUNCTION(stripslashes,
                     const String& str) {
  if (str.empty()) {
    return str;
  }

  return stringForEachBuffered(str.size(), str,
    [&] (StringBuffer& ret, const char*& src, const char* end) {
      if (*src == '\\' && *++src == '0') {
        ret.append('\0');
        return;
      }
      if (src < end) {
        ret.append(*src);
      }
    });
}


  bool ensureTraceSpace() {
    bool track_realloc = false;
    if (m_traceBufferFilled) {
      m_overflowCalls++;
      return false;
    }
    int new_array_size;
    if (m_traceBufferSize == 0) {
      new_array_size = RuntimeOption::ProfilerTraceBuffer;
    } else {
      new_array_size = m_traceBufferSize *
        RuntimeOption::ProfilerTraceExpansion;
      if (m_maxTraceBuffer != 0 && new_array_size > m_maxTraceBuffer) {
        new_array_size = m_maxTraceBuffer > m_traceBufferSize ?
          m_maxTraceBuffer : m_traceBufferSize;
      }
      if (new_array_size - m_nextTraceEntry <= 5) {
        // for this operation to succeed, we need room for the entry we're
        // adding, two realloc entries, and two entries to mark the end of
        // the trace.
        m_traceBufferFilled = true;
        collectStats("(trace buffer terminated)", false,
                     m_traceBuffer[m_nextTraceEntry++]);
        return false;
      }
      track_realloc = true;
    }
    if (track_realloc) {
      collectStats("(trace buffer realloc)", false,
                   m_traceBuffer[m_nextTraceEntry++]);
    }
    {
      MemoryManager::MaskAlloc masker(*tl_heap);
      auto r = (TraceEntry*)realloc((void*)m_traceBuffer,
                                    new_array_size * sizeof(TraceEntry));

      if (!r) {
        m_traceBufferFilled = true;
        if (m_traceBuffer) {
          collectStats("(trace buffer terminated)", false,
                       m_traceBuffer[m_nextTraceEntry++]);
        }
        return false;
      }
      m_traceBufferSize = new_array_size;
      m_traceBuffer = r;
    }
    if (track_realloc) {
      collectStats("(trace buffer realloc)", true,
                   m_traceBuffer[m_nextTraceEntry++]);
    }
    return true;
  }

#define HP_STACK_DELIM_LEN    (sizeof(HP_STACK_DELIM) - 1)


  /* implicit */ String(folly::StringPiece s)
  : m_str(StringData::Make(s), NoIncRef{}) {}

String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

friend String&& operator

friend String

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;

struct StrNR {
private:
  StringData *m_px;

public:
  StrNR() : m_px(nullptr) {}
  explicit StrNR(StringData *sd) : m_px(sd) {}
  explicit StrNR(const StringData *sd) : m_px(const_cast<StringData*>(sd)) {}
  explicit StrNR(const String &s) : m_px(s.get()) {} // XXX
  explicit StrNR(const char*) = delete;

  ~StrNR() {
    if (debug) {
      m_px = reinterpret_cast<StringData*>(0xdeadbeeffaceb004);
    }
  }

  /* implicit */ operator

inline String& String::operator=(const StaticString& v)


static int hphp_gdImageConvolution(gdImagePtr src, float filter[3][3],
                                   float filter_div, float offset) {
  int x, y, i, j, new_a;
  float new_r, new_g, new_b;
  int new_pxl, pxl=0;
  gdImagePtr srcback;

  if (src==nullptr) {
    return 0;
  }

  /* We need the orinal image with each safe neoghb. pixel */
  srcback = gdImageCreateTrueColor (src->sx, src->sy);
  gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);

  if (srcback==nullptr) {
    return 0;
  }

  for ( y=0; y<src->sy; y++) {
    for(x=0; x<src->sx; x++) {
      new_r = new_g = new_b = 0;
      new_a = gdImageAlpha(srcback, pxl);

      for (j=0; j<3; j++) {
        int yv = std::min(std::max(y - 1 + j, 0), src->sy - 1);
        for (i=0; i<3; i++) {
          pxl = gdImageGetPixel(srcback, std::min(std::max(x - 1 + i, 0),
                                                  src->sx - 1), yv);
          new_r += (float)gdImageRed(srcback, pxl) * filter[j][i];
          new_g += (float)gdImageGreen(srcback, pxl) * filter[j][i];
          new_b += (float)gdImageBlue(srcback, pxl) * filter[j][i];
        }
      }

      new_r = (new_r/filter_div)+offset;
      new_g = (new_g/filter_div)+offset;
      new_b = (new_b/filter_div)+offset;

      new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
      new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
      new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);

      new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g,
                                          (int)new_b, new_a);
      if (new_pxl == -1) {
        new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g,
                                          (int)new_b, new_a);
      }
      gdImageSetPixel (src, x, y, new_pxl);
    }
  }
  gdImageDestroy(srcback);
  return 1;
}


  void moduleInit() override {
    HHVM_FE(gd_info);
    HHVM_FE(getimagesize);
    HHVM_FE(getimagesizefromstring);
    HHVM_FE(image_type_to_extension);
    HHVM_FE(image_type_to_mime_type);
    HHVM_FE(image2wbmp);
    HHVM_FE(imageaffine);
    HHVM_FE(imageaffinematrixconcat);
    HHVM_FE(imageaffinematrixget);
    HHVM_FE(imagealphablending);
    HHVM_FE(imageantialias);
    HHVM_FE(imagearc);
    HHVM_FE(imagechar);
    HHVM_FE(imagecharup);
    HHVM_FE(imagecolorallocate);
    HHVM_FE(imagecolorallocatealpha);
    HHVM_FE(imagecolorat);
    HHVM_FE(imagecolorclosest);
    HHVM_FE(imagecolorclosestalpha);
    HHVM_FE(imagecolorclosesthwb);
    HHVM_FE(imagecolordeallocate);
    HHVM_FE(imagecolorexact);
    HHVM_FE(imagecolorexactalpha);
    HHVM_FE(imagecolormatch);
    HHVM_FE(imagecolorresolve);
    HHVM_FE(imagecolorresolvealpha);
    HHVM_FE(imagecolorset);
    HHVM_FE(imagecolorsforindex);
    HHVM_FE(imagecolorstotal);
    HHVM_FE(imagecolortransparent);
    HHVM_FE(imageconvolution);
    HHVM_FE(imagecopy);
    HHVM_FE(imagecopymerge);
    HHVM_FE(imagecopymergegray);
    HHVM_FE(imagecopyresampled);
    HHVM_FE(imagecopyresized);
    HHVM_FE(imagecreate);
    HHVM_FE(imagecreatefromgd2part);
    HHVM_FE(imagecreatefromgd);
    HHVM_FE(imagecreatefromgd2);
    HHVM_FE(imagecreatefromgif);
#ifdef HAVE_GD_JPG
    HHVM_FE(imagecreatefromjpeg);
#endif
#ifdef HAVE_GD_PNG
    HHVM_FE(imagecreatefrompng);
#endif
#ifdef HAVE_LIBVPX
    HHVM_FE(imagecreatefromwebp);
#endif
    HHVM_FE(imagecreatefromstring);
    HHVM_FE(imagecreatefromwbmp);
    HHVM_FE(imagecreatefromxbm);
#if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED)
    HHVM_FE(imagecreatefromxpm);
#endif
    HHVM_FE(imagecreatetruecolor);
    HHVM_FE(imagecrop);
    HHVM_FE(imagecropauto);
    HHVM_FE(imagedashedline);
    HHVM_FE(imagedestroy);
    HHVM_FE(imageellipse);
    HHVM_FE(imagefill);
    HHVM_FE(imagefilledarc);
    HHVM_FE(imagefilledellipse);
    HHVM_FE(imagefilledpolygon);
    HHVM_FE(imagefilledrectangle);
    HHVM_FE(imagefilltoborder);
    HHVM_FE(imagefilledellipse);
    HHVM_FE(imagefilledpolygon);
    HHVM_FE(imagefilledrectangle);
    HHVM_FE(imagefilltoborder);
    HHVM_FE(imagefilter);
    HHVM_FE(imageflip);
    HHVM_FE(imagefontheight);
    HHVM_FE(imagefontwidth);
#if defined(ENABLE_GD_TTF) && HAVE_LIBFREETYPE
    HHVM_FE(imageftbbox);
    HHVM_FE(imagefttext);
#endif
    HHVM_FE(imagegammacorrect);
    HHVM_FE(imagegd2);
    HHVM_FE(imagegd);
    HHVM_FE(imagegif);
    HHVM_FE(imageinterlace);
    HHVM_FE(imageistruecolor);
#ifdef HAVE_GD_JPG
    HHVM_FE(imagejpeg);
#endif
    HHVM_FE(imagelayereffect);
    HHVM_FE(imageline);
    HHVM_FE(imageloadfont);
#ifdef HAVE_GD_PNG
    HHVM_FE(imagepng);
#endif
#ifdef HAVE_LIBVPX
    HHVM_FE(imagewebp);
#endif
    HHVM_FE(imagepolygon);
    HHVM_FE(imagerectangle);
    HHVM_FE(imagerotate);
    HHVM_FE(imagesavealpha);
    HHVM_FE(imagescale);
    HHVM_FE(imagesetbrush);
    HHVM_FE(imagesetinterpolation);
    HHVM_FE(imagesetpixel);
    HHVM_FE(imagesetstyle);
    HHVM_FE(imagesetthickness);
    HHVM_FE(imagesettile);
    HHVM_FE(imagestring);
    HHVM_FE(imagestringup);
    HHVM_FE(imagesx);
    HHVM_FE(imagesy);
    HHVM_FE(imagetruecolortopalette);
#ifdef ENABLE_GD_TTF
    HHVM_FE(imagettfbbox);
    HHVM_FE(imagettftext);
#endif
    HHVM_FE(imagetypes);
    HHVM_FE(imagewbmp);

    HHVM_FE(iptcembed);
    HHVM_FE(iptcparse);

    HHVM_FE(jpeg2wbmp);
    HHVM_FE(png2wbmp);

    HHVM_FE(imagepalettecopy);

    HHVM_RC_INT(IMG_GIF, IMAGE_TYPE_GIF);
    HHVM_RC_INT(IMG_JPG, IMAGE_TYPE_JPEG);
    HHVM_RC_INT(IMG_JPEG, IMAGE_TYPE_JPEG);
    HHVM_RC_INT(IMG_PNG, IMAGE_TYPE_PNG);
    HHVM_RC_INT(IMG_WBMP, IMAGE_TYPE_WBMP);
    HHVM_RC_INT(IMG_XPM, IMAGE_TYPE_XPM);

    /* special colours for gd */
    HHVM_RC_INT(IMG_COLOR_TILED, gdTiled);
    HHVM_RC_INT(IMG_COLOR_STYLED, gdStyled);
    HHVM_RC_INT(IMG_COLOR_BRUSHED, gdBrushed);
    HHVM_RC_INT(IMG_COLOR_STYLEDBRUSHED, gdStyledBrushed);
    HHVM_RC_INT(IMG_COLOR_TRANSPARENT, gdTransparent);

    /* for imagefilledarc */
    HHVM_RC_INT(IMG_ARC_ROUNDED, gdArc);
    HHVM_RC_INT(IMG_ARC_PIE, gdPie);
    HHVM_RC_INT(IMG_ARC_CHORD, gdChord);
    HHVM_RC_INT(IMG_ARC_NOFILL, gdNoFill);
    HHVM_RC_INT(IMG_ARC_EDGED, gdEdged);

    /* GD2 image format types */
    HHVM_RC_INT(IMG_GD2_RAW, GD2_FMT_RAW);
    HHVM_RC_INT(IMG_GD2_COMPRESSED, GD2_FMT_COMPRESSED);
    HHVM_RC_INT(IMG_FLIP_HORIZONTAL, GD_FLIP_HORINZONTAL);
    HHVM_RC_INT(IMG_FLIP_VERTICAL, GD_FLIP_VERTICAL);
    HHVM_RC_INT(IMG_FLIP_BOTH, GD_FLIP_BOTH);
    HHVM_RC_INT(IMG_EFFECT_REPLACE, gdEffectReplace);
    HHVM_RC_INT(IMG_EFFECT_ALPHABLEND, gdEffectAlphaBlend);
    HHVM_RC_INT(IMG_EFFECT_NORMAL, gdEffectNormal);
    HHVM_RC_INT(IMG_EFFECT_OVERLAY, gdEffectOverlay);

    HHVM_RC_INT(IMG_CROP_DEFAULT, GD_CROP_DEFAULT);
    HHVM_RC_INT(IMG_CROP_TRANSPARENT, GD_CROP_TRANSPARENT);
    HHVM_RC_INT(IMG_CROP_BLACK, GD_CROP_BLACK);
    HHVM_RC_INT(IMG_CROP_WHITE, GD_CROP_WHITE);
    HHVM_RC_INT(IMG_CROP_SIDES, GD_CROP_SIDES);
    HHVM_RC_INT(IMG_CROP_THRESHOLD, GD_CROP_THRESHOLD);

    HHVM_RC_INT(IMG_BELL, GD_BELL);
    HHVM_RC_INT(IMG_BESSEL, GD_BESSEL);
    HHVM_RC_INT(IMG_BILINEAR_FIXED, GD_BILINEAR_FIXED);
    HHVM_RC_INT(IMG_BICUBIC, GD_BICUBIC);
    HHVM_RC_INT(IMG_BICUBIC_FIXED, GD_BICUBIC_FIXED);
    HHVM_RC_INT(IMG_BLACKMAN, GD_BLACKMAN);
    HHVM_RC_INT(IMG_BOX, GD_BOX);
    HHVM_RC_INT(IMG_BSPLINE, GD_BSPLINE);
    HHVM_RC_INT(IMG_CATMULLROM, GD_CATMULLROM);
    HHVM_RC_INT(IMG_GAUSSIAN, GD_GAUSSIAN);
    HHVM_RC_INT(IMG_GENERALIZED_CUBIC, GD_GENERALIZED_CUBIC);
    HHVM_RC_INT(IMG_HERMITE, GD_HERMITE);
    HHVM_RC_INT(IMG_HAMMING, GD_HAMMING);
    HHVM_RC_INT(IMG_HANNING, GD_HANNING);
    HHVM_RC_INT(IMG_MITCHELL, GD_MITCHELL);
    HHVM_RC_INT(IMG_POWER, GD_POWER);
    HHVM_RC_INT(IMG_QUADRATIC, GD_QUADRATIC);
    HHVM_RC_INT(IMG_SINC, GD_SINC);
    HHVM_RC_INT(IMG_NEAREST_NEIGHBOUR, GD_NEAREST_NEIGHBOUR);
    HHVM_RC_INT(IMG_WEIGHTED4, GD_WEIGHTED4);
    HHVM_RC_INT(IMG_TRIANGLE, GD_TRIANGLE);

    HHVM_RC_INT(IMG_AFFINE_TRANSLATE, GD_AFFINE_TRANSLATE);
    HHVM_RC_INT(IMG_AFFINE_SCALE, GD_AFFINE_SCALE);
    HHVM_RC_INT(IMG_AFFINE_ROTATE, GD_AFFINE_ROTATE);
    HHVM_RC_INT(IMG_AFFINE_SHEAR_HORIZONTAL, GD_AFFINE_SHEAR_HORIZONTAL);
    HHVM_RC_INT(IMG_AFFINE_SHEAR_VERTICAL, GD_AFFINE_SHEAR_VERTICAL);

    HHVM_RC_INT(IMG_FILTER_BRIGHTNESS, IMAGE_FILTER_BRIGHTNESS);
    HHVM_RC_INT(IMG_FILTER_COLORIZE, IMAGE_FILTER_COLORIZE);
    HHVM_RC_INT(IMG_FILTER_CONTRAST, IMAGE_FILTER_CONTRAST);
    HHVM_RC_INT(IMG_FILTER_EDGEDETECT, IMAGE_FILTER_EDGEDETECT);
    HHVM_RC_INT(IMG_FILTER_EMBOSS, IMAGE_FILTER_EMBOSS);
    HHVM_RC_INT(IMG_FILTER_GAUSSIAN_BLUR, IMAGE_FILTER_GAUSSIAN_BLUR);
    HHVM_RC_INT(IMG_FILTER_GRAYSCALE, IMAGE_FILTER_GRAYSCALE);
    HHVM_RC_INT(IMG_FILTER_MEAN_REMOVAL, IMAGE_FILTER_MEAN_REMOVAL);
    HHVM_RC_INT(IMG_FILTER_NEGATE, IMAGE_FILTER_NEGATE);
    HHVM_RC_INT(IMG_FILTER_SELECTIVE_BLUR, IMAGE_FILTER_SELECTIVE_BLUR);
    HHVM_RC_INT(IMG_FILTER_SMOOTH, IMAGE_FILTER_SMOOTH);
    HHVM_RC_INT(IMG_FILTER_PIXELATE, IMAGE_FILTER_PIXELATE);

    HHVM_RC_INT(IMAGETYPE_GIF, IMAGE_FILETYPE_GIF);
    HHVM_RC_INT(IMAGETYPE_JPEG, IMAGE_FILETYPE_JPEG);
    HHVM_RC_INT(IMAGETYPE_PNG, IMAGE_FILETYPE_PNG);
    HHVM_RC_INT(IMAGETYPE_SWF, IMAGE_FILETYPE_SWF);
    HHVM_RC_INT(IMAGETYPE_PSD, IMAGE_FILETYPE_PSD);
    HHVM_RC_INT(IMAGETYPE_BMP, IMAGE_FILETYPE_BMP);
    HHVM_RC_INT(IMAGETYPE_TIFF_II, IMAGE_FILETYPE_TIFF_II);
    HHVM_RC_INT(IMAGETYPE_TIFF_MM, IMAGE_FILETYPE_TIFF_MM);
    HHVM_RC_INT(IMAGETYPE_JPC, IMAGE_FILETYPE_JPC);
    HHVM_RC_INT(IMAGETYPE_JP2, IMAGE_FILETYPE_JP2);
    HHVM_RC_INT(IMAGETYPE_JPX, IMAGE_FILETYPE_JPX);
    HHVM_RC_INT(IMAGETYPE_JB2, IMAGE_FILETYPE_JB2);
    HHVM_RC_INT(IMAGETYPE_IFF, IMAGE_FILETYPE_IFF);
    HHVM_RC_INT(IMAGETYPE_WBMP, IMAGE_FILETYPE_WBMP);
    HHVM_RC_INT(IMAGETYPE_XBM, IMAGE_FILETYPE_XBM);
    HHVM_RC_INT(IMAGETYPE_ICO, IMAGE_FILETYPE_ICO);
    HHVM_RC_INT(IMAGETYPE_UNKNOWN, IMAGE_FILETYPE_UNKNOWN);
    HHVM_RC_INT(IMAGETYPE_COUNT, IMAGE_FILETYPE_COUNT);
    HHVM_RC_INT(IMAGETYPE_SWC, IMAGE_FILETYPE_SWC);
    HHVM_RC_INT(IMAGETYPE_JPEG2000, IMAGE_FILETYPE_JPC);

#ifdef GD_VERSION_STRING
    HHVM_RC_STR(GD_VERSION, GD_VERSION_STRING);
#endif

#if defined(GD_MAJOR_VERSION) && defined(GD_MINOR_VERSION) && \
    defined(GD_RELEASE_VERSION) && defined(GD_EXTRA_VERSION)
    HHVM_RC_INT_SAME(GD_MAJOR_VERSION);
    HHVM_RC_INT_SAME(GD_MINOR_VERSION);
    HHVM_RC_INT_SAME(GD_RELEASE_VERSION);
    HHVM_RC_STR_SAME(GD_EXTRA_VERSION);
#endif

#ifdef HAVE_GD_PNG
    HHVM_RC_INT(PNG_NO_FILTER, 0x00);
    HHVM_RC_INT(PNG_FILTER_NONE, 0x08);
    HHVM_RC_INT(PNG_FILTER_SUB, 0x10);
    HHVM_RC_INT(PNG_FILTER_UP, 0x20);
    HHVM_RC_INT(PNG_FILTER_AVG, 0x40);
    HHVM_RC_INT(PNG_FILTER_PAETH, 0x80);
    HHVM_RC_INT(PNG_ALL_FILTERS, 0x08 | 0x10 | 0x20 | 0x40 | 0x80);
#endif

    HHVM_RC_BOOL(GD_BUNDLED, true);

    loadSystemlib();
  }

#define IMAGE_FILTER_NEGATE         0

#define IMAGE_FILTER_GRAYSCALE      1

#define IMAGE_FILTER_BRIGHTNESS     2

#define IMAGE_FILTER_CONTRAST       3

#define IMAGE_FILTER_COLORIZE       4

#define IMAGE_FILTER_EDGEDETECT     5

#define IMAGE_FILTER_EMBOSS         6

#define IMAGE_FILTER_GAUSSIAN_BLUR  7

#define IMAGE_FILTER_SELECTIVE_BLUR 8

#define IMAGE_FILTER_MEAN_REMOVAL   9

#define IMAGE_FILTER_SMOOTH         10

#define IMAGE_FILTER_PIXELATE       11

#define IMAGE_TYPE_GIF 1

#define IMAGE_TYPE_JPEG 2

#define IMAGE_TYPE_PNG 4

#define IMAGE_TYPE_WBMP 8

#define IMAGE_TYPE_XPM 16


inline StringData::Proxy* StringData::proxy() {
  return static_cast<Proxy*>(payload());
}


Variant HHVM_FUNCTION(imagecolorstotal, const Resource& image) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  return (gdImageColorsTotal(im));
}


Variant HHVM_FUNCTION(HH_last, const Variant& v) {
  // 1. array, vec, dict, keyset
  if (v.isArray() || v.isClsMeth()) {
    auto arr = v.toArray();
    if (arr->empty()) {
      return init_null();
    }
    return arr->getValue(arr->iter_last());
  }

  if (v.isObject()) {
    auto obj = v.asCObjRef();
    // 2. collection
    if (obj->isCollection()) {
      // Pair
      if (obj->collectionType() == CollectionType::Pair) {
        auto const pair = static_cast<c_Pair*>(obj.get());
        return Variant::wrap(*pair->at(1));
      }

      // Vector, Map, Set, and Imm variants
      auto arr = collections::asArray(obj.get());
      if (arr->empty()) {
        return init_null();
      }
      return arr->getValue(arr->iter_last());
    }
  }
  SystemLib::throwInvalidArgumentExceptionObject(
    "Argument 1 passed to HH\\Lib\\_Private\\Native\\last() "
    "must be a Container");
}


bool HHVM_FUNCTION(imageellipse, const Resource& image,
    int64_t cx, int64_t cy, int64_t width, int64_t height, int64_t color) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  color = SetupAntiAliasedColor(im, color);
  gdImageArc(im, cx, cy, width, height, 0, 360, color);
  return true;
}


Variant socket_server_impl(
  const HostURL &hosturl,
  int flags,
  Variant& errnum,
  Variant& errstr,
  const Variant& context /* = uninit_variant */
) {
  errnum = 0;
  errstr = empty_string();
  auto sock = create_new_socket(hosturl, errnum, errstr, context);
  if (!sock) {
    return false;
  }

  sockaddr_storage sa_storage;
  struct sockaddr *sa_ptr;
  size_t sa_size;
  if (!set_sockaddr(sa_storage, sock, hosturl.getHost(),
                    hosturl.getPort(), sa_ptr, sa_size)) {
    return false;
  }
  int yes = 1;
  setsockopt(sock->fd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
  if ((flags & k_STREAM_SERVER_BIND) != 0 &&
      ::bind(sock->fd(), sa_ptr, sa_size) < 0) {
    SOCKET_ERROR(sock, "unable to bind to given address", errno);
    return false;
  }
  if ((flags & k_STREAM_SERVER_LISTEN) != 0 && listen(sock->fd(), 128) < 0) {
    SOCKET_ERROR(sock, "unable to listen on socket", errno);
    return false;
  }

  return Variant(std::move(sock));
}


Variant HHVM_FUNCTION(imagecolormatch, const Resource& image1,
                                       const Resource& image2) {
  gdImagePtr im1 = get_valid_image_resource(image1);
  if (!im1) return false;
  gdImagePtr im2 = get_valid_image_resource(image2);
  if (!im2) return false;
  int result;

  result = gdImageColorMatch(im1, im2);
  switch (result) {
  case -1:
    raise_warning("Image1 must be TrueColor");
    return false;
  case -2:
    raise_warning("Image2 must be Palette");
    return false;
  case -3:
    raise_warning("Image1 and Image2 must be the same size");
    return false;
  case -4:
    raise_warning("Image2 must have at least one color");
    return false;
  }

  return true;
}


int string_natural_cmp(char const *a, size_t a_len,
                       char const *b, size_t b_len, int fold_case) {
  char ca, cb;
  char const *ap, *bp;
  char const *aend = a + a_len, *bend = b + b_len;
  int fractional, result;

  if (a_len == 0 || b_len == 0)
    return a_len - b_len;

  ap = a;
  bp = b;
  while (1) {
    ca = *ap; cb = *bp;

    /* skip over leading spaces or zeros */
    while (isspace((int)(unsigned char)ca))
      ca = *++ap;

    while (isspace((int)(unsigned char)cb))
      cb = *++bp;

    /* process run of digits */
    if (isdigit((int)(unsigned char)ca)  &&  isdigit((int)(unsigned char)cb)) {
      fractional = (ca == '0' || cb == '0');

      if (fractional)
        result = compare_left(&ap, aend, &bp, bend);
      else
        result = compare_right(&ap, aend, &bp, bend);

      if (result != 0)
        return result;
      else if (ap == aend && bp == bend)
        /* End of the strings. Let caller sort them out. */
        return 0;
      else {
        /* Keep on comparing from the current point. */
        ca = *ap; cb = *bp;
      }
    }

    if (fold_case) {
      ca = toupper((int)(unsigned char)ca);
      cb = toupper((int)(unsigned char)cb);
    }

    if (ca < cb)
      return -1;
    else if (ca > cb)
      return +1;

    ++ap; ++bp;
    if (ap >= aend && bp >= bend)
      /* The strings compare the same.  Perhaps the caller
         will want to call strcmp to break the tie. */
      return 0;
    else if (ap >= aend)
      return -1;
    else if (bp >= bend)
      return 1;
  }
}


bool socket_create_pair_impl(int domain, int type, int protocol, Variant& fd,
                             bool asStream) {
  check_socket_parameters(domain, type);

  int fds_array[2];
  if (socketpair(domain, type, protocol, fds_array) != 0) {
    SOCKET_ERROR(req::make<StreamSocket>(),
                 "unable to create socket pair",
                 errno);
    return false;
  }

  if (asStream) {
    fd = make_varray(
      Variant(req::make<StreamSocket>(fds_array[0], domain, nullptr, 0, 0.0,
                                      s_socktype_generic)),
      Variant(req::make<StreamSocket>(fds_array[1], domain, nullptr, 0, 0.0,
                                      s_socktype_generic))
    );
  } else {
    fd = make_varray(
      Variant(req::make<ConcreteSocket>(fds_array[0], domain, nullptr, 0, 0.0,
                                        s_socktype_generic)),
      Variant(req::make<ConcreteSocket>(fds_array[1], domain, nullptr, 0, 0.0,
                                        s_socktype_generic))
    );
  }
  return true;
}


void Profiler::beginFrameEx(const char* /*symbol*/) {}


inline strhash_t StringData::hash(const char* s, size_t len) {
  return hash_string_i(s, len);
}


bool str_contains_any_of(const String& haystack, const String& char_list) {
  return strpbrk_impl<true>(haystack, char_list).toBooleanVal();
}


Variant HHVM_FUNCTION(mcrypt_enc_get_algorithms_name, const Resource& td) {
  auto pm = get_valid_mcrypt_resource(td);
  if (!pm) {
    return false;
  }

  char *name = mcrypt_enc_get_algorithms_name(pm->m_td);
  String ret(name, CopyString);
  mcrypt_free(name);
  return ret;
}


void HHVM_FUNCTION(debug_zval_dump, const Variant& variable) {
  VariableSerializer vs(VariableSerializer::Type::DebugDump);
  vs.serialize(variable, false);
}


  const char *c_str() const {
    return m_str ? m_str->data() : "";
  }


  bool isNumeric() const {
    return m_str ? m_str->isNumeric() : false;
  }


void HHVM_FUNCTION(socket_close,
                   const Resource& socket) {
  cast<Socket>(socket)->close();
}


String HHVM_FUNCTION(hhvm_intrinsics_serialize_keep_dvarrays,
                     const Variant& value) {
  SerializeOptions opts;
  opts.keepDVArrays = true;
  return serialize_impl(value, opts);
}


bool HHVM_FUNCTION(imagepolygon, const Resource& image,
    const Array& points, int64_t num_points, int64_t color) {
  return php_imagepolygon(image, points, num_points, color, 0);
}


static bool preg_get_backref(const char** str, int* backref) {
  char in_brace = 0;
  const char* walk = *str;

  if (walk[1] == 0) {
    return false;
  }

  if (*walk == '$' && walk[1] == '{') {
    in_brace = 1;
    walk++;
  }
  walk++;

  if (*walk >= '0' && *walk <= '9') {
    *backref = *walk - '0';
    walk++;
  } else {
    return false;
  }

  if (*walk && *walk >= '0' && *walk <= '9') {
    *backref = *backref * 10 + *walk - '0';
    walk++;
  }

  if (in_brace) {
    if (*walk == 0 || *walk != '}') {
      return false;
    }
    walk++;
  }

  *str = walk;
  return true;
}


Variant HHVM_FUNCTION(mcrypt_enc_get_modes_name, const Resource& td) {
  auto pm = get_valid_mcrypt_resource(td);
  if (!pm) {
    return false;
  }

  char *name = mcrypt_enc_get_modes_name(pm->m_td);
  String ret(name, CopyString);
  mcrypt_free(name);
  return ret;
}


Variant HHVM_FUNCTION(imagecolorclosesthwb, const Resource& image,
    int64_t red, int64_t green, int64_t blue) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  return gdImageColorClosestHWB(im, red, green, blue);
}


static tag_table_type exif_get_tag_table(int section) {
  switch(section) {
  case SECTION_FILE:      return &tag_table_IFD[0];
  case SECTION_COMPUTED:  return &tag_table_IFD[0];
  case SECTION_ANY_TAG:   return &tag_table_IFD[0];
  case SECTION_IFD0:      return &tag_table_IFD[0];
  case SECTION_THUMBNAIL: return &tag_table_IFD[0];
  case SECTION_COMMENT:   return &tag_table_IFD[0];
  case SECTION_APP0:      return &tag_table_IFD[0];
  case SECTION_EXIF:      return &tag_table_IFD[0];
  case SECTION_FPIX:      return &tag_table_IFD[0];
  case SECTION_GPS:       return &tag_table_GPS[0];
  case SECTION_INTEROP:   return &tag_table_IOP[0];
  case SECTION_APP12:     return &tag_table_IFD[0];
  case SECTION_WINXP:     return &tag_table_IFD[0];
  }
  return &tag_table_IFD[0];
}


struct CSRequest : SweepableResourceData {
private:
  X509_REQ *m_csr;

public:
  explicit CSRequest(X509_REQ *csr) : m_csr(csr) {
    assertx(m_csr);
  }

  X509_REQ *csr() { return m_csr; }

  ~CSRequest() override {
    // X509_REQ_free(nullptr) is a no-op
    X509_REQ_free(m_csr);
  }

  CLASSNAME_IS("OpenSSL X.509 CSR");
  // overriding ResourceData
  const String& o_getClassNameHook() const override { return classnameof(); }

  DECLARE_RESOURCE_ALLOCATION(CSRequest)

  static req::ptr<CSRequest> Get(const Variant& var) {
    auto csr = cast_or_null<CSRequest>(GetRequest(var));
    if (!csr || !csr->m_csr) {
      raise_warning("cannot get CSR");
      return nullptr;
    }
    return csr;
  }

private:
  static req::ptr<CSRequest> GetRequest(const Variant& var) {
    if (var.isResource()) {
      return dyn_cast_or_null<CSRequest>(var);
    }
    if (var.isString() || var.isObject()) {
      BIO *in = Certificate::ReadData(var);
      if (in == nullptr) return nullptr;

      X509_REQ *csr = PEM_read_bio_X509_REQ(in, nullptr,nullptr,nullptr);
      BIO_free(in);
      if (csr) {
        return req::make<CSRequest>(csr);
      }
    }
    return nullptr;
  }
}


static req::ptr<Socket> create_new_socket(
  const HostURL &hosturl,
  Variant& errnum,
  Variant& errstr,
  const Variant& context
) {
  int domain = hosturl.isIPv6() ? AF_INET6 : AF_INET;
  int type = SOCK_STREAM;
  const std::string scheme = hosturl.getScheme();

  if (scheme == "udp" || scheme == "udg") {
    type = SOCK_DGRAM;
  }

  if (scheme == "unix" || scheme == "udg") {
    domain = AF_UNIX;
  }

  req::ptr<Socket> sock;
  int fd = socket(domain, type, 0);
  double timeout = RequestInfo::s_requestInfo.getNoCheck()->
      m_reqInjectionData.getSocketDefaultTimeout();
  req::ptr<StreamContext> streamctx;
  if (context.isResource()) {
    streamctx = cast<StreamContext>(context.toResource());
  }

  auto sslsock = SSLSocket::Create(fd, domain, hosturl, timeout, streamctx);
  if (sslsock) {
    sock = sslsock;
  } else {
    sock = req::make<StreamSocket>(fd, domain, hosturl.getHost().c_str(),
                                   hosturl.getPort());
  }

  if (!sock->valid()) {
    SOCKET_ERROR(sock, "unable to create socket", errno);
    errnum = sock->getError();
    errstr = HHVM_FN(socket_strerror)(sock->getError());
    sock.reset();
  }
  return sock;
}


  void imDump(void *ptrs[], int &n) {
    int i = 0;
    for (auto iter = m_alloced.begin(); iter != m_alloced.end(); ++i, ++iter) {
      void *p = *iter;
      assertx(p);
      if (i < n) ptrs[i] = p;
      int ln;
      size_t size;
      memcpy(&ln, p, sizeof(ln));
      memcpy(&size, (char*)p + sizeof(ln), sizeof(size));
      printf("%d: (%p, %lu)\n", ln, p, size);
    }
    n = (i < n) ? i : n;
  }


Variant HHVM_FUNCTION(mcrypt_cfb, const String& cipher, const String& key,
                                  const String& data, const Variant& mode,
                                  const Variant& viv /* = null_string */) {
  raise_deprecated("Function mcrypt_cfb() is deprecated");
  String iv = viv.toString();
  return php_mcrypt_do_crypt(cipher, key, data, "cfb", iv, mode.toInt32(),
                             "mcrypt_cfb");
}


Variant HHVM_FUNCTION(imagecreatefromxpm, const String& filename) {
  gdImagePtr im =
    _php_image_create_from(filename, -1, -1, -1, -1,
                           PHP_GDIMG_TYPE_XPM, "XPM",
                           (gdImagePtr(*)())gdImageCreateFromXpm,
                           (gdImagePtr(*)())nullptr);
  if (im == nullptr) {
    return false;
  }
  return Variant(req::make<Image>(im));
}


String HHVM_FUNCTION(HH_serialize_with_options,
                     const Variant& value, const Array& options) {
  SerializeOptions opts;
  opts.keepDVArrays = options.exists(s_keepDVArrays) &&
    options[s_keepDVArrays].toBoolean();
  opts.forcePHPArrays = options.exists(s_forcePHPArrays) &&
    options[s_forcePHPArrays].toBoolean();
  opts.warnOnHackArrays = options.exists(s_warnOnHackArrays) &&
    options[s_warnOnHackArrays].toBoolean();
  opts.warnOnPHPArrays = options.exists(s_warnOnPHPArrays) &&
    options[s_warnOnPHPArrays].toBoolean();
  opts.ignoreLateInit = options.exists(s_ignoreLateInit) &&
    options[s_ignoreLateInit].toBoolean();
  opts.serializeProvenanceAndLegacy =
    options.exists(s_serializeProvenanceAndLegacy) &&
    options[s_serializeProvenanceAndLegacy].toBoolean();
  return serialize_impl(value, opts);
}


int64_t HHVM_FUNCTION(socket_last_error,
                      const Variant& socket /* = null */) {
  if (!socket.isNull()) {
    return cast<Socket>(socket)->getError();
  }
  return Socket::getLastError();
}


  void endFrame(const TypedValue* /*retval*/, const char* symbol,
                bool /*endMain*/ = false) override {
    doTrace(symbol, true);
  }


TypedValue HHVM_FUNCTION(strncasecmp,
                         const String& str1,
                         const String& str2,
                         int len) {
  if (len < 0) {
    raise_warning("Length must be greater than or equal to 0");
    return make_tv<KindOfBoolean>(false);
  }
  return tvReturn(string_strncasecmp(
    str1.data(), str1.size(),
    str2.data(), str2.size(), len
  ));
}


  void writeStats(Array& /*ret*/) override {
    fprintf(stderr, "writeStats start\n");
    // RetSame: the return value is the same instance every time
    // HasThis: call has a this argument
    // AllSame: all returns were the same data even though args are different
    // MemberCount: number of different arg sets (including this)
    fprintf(stderr, "Count Function MinSerLen MaxSerLen RetSame HasThis "
            "AllSame MemberCount\n");
    for (auto& me : m_memos) {
      if (me.second.m_ignore) continue;
      if (me.second.m_count == 1) continue;
      int min_ser_len = 999999999;
      int max_ser_len = 0;
      int count = 0;
      int member_count = 0;
      bool all_same = true;
      if (me.second.m_has_this) {
        bool any_multiple = false;
        auto& fr = me.second.m_member_memos.begin()->second.m_return_value;
        member_count = me.second.m_member_memos.size();
        for (auto& mme : me.second.m_member_memos) {
          if (mme.second.m_return_value != fr) all_same = false;
          count += mme.second.m_count;
          auto ser_len = mme.second.m_return_value.length();
          min_ser_len = std::min<int64_t>(min_ser_len, ser_len);
          max_ser_len = std::max<int64_t>(max_ser_len, ser_len);
          if (mme.second.m_count > 1) any_multiple = true;
        }
        if (!any_multiple && !all_same) continue;
      } else {
        min_ser_len = max_ser_len = me.second.m_return_value.length();
        count = me.second.m_count;
        all_same = me.second.m_ret_tv_same;
      }
      fprintf(stderr, "%d %s %d %d %s %s %s %d\n",
              count, me.first.data(),
              min_ser_len, max_ser_len,
              me.second.m_ret_tv_same ? " true" : "false",
              me.second.m_has_this ? " true" : "false",
              all_same ? " true" : "false",
              member_count
             );
    }
    fprintf(stderr, "writeStats end\n");
  }


bool HHVM_FUNCTION(HH_is_vec, const Variant& v) {
  return is_vec(v.asTypedValue());
}


static int get_php_tiff_bytes_per_format(int format) {
  int size = sizeof(php_tiff_bytes_per_format)/sizeof(int);
  if (format >= size) {
    raise_warning("Invalid format %d", format);
    format = 0;
  }
  return php_tiff_bytes_per_format[format];
}


bool HHVM_FUNCTION(is_scalar, const Variant& v) {
  return v.isScalar();
}


pcre_literal_data::pcre_literal_data(const char* pattern, int coptions) {
  if (coptions & ~PCRE_CASELESS) {
    return;
  }

  auto p = pattern;
  if (*p == '^') {
    match_start = true;
    p++;
  }

  std::string pattern_buffer;
  while (isalnum((unsigned char)*p) || (*p && strchr("/\\ :-_", *p))) {
    // backslash + alphanumeric character --> not a literal (i.e. \d).
    // backslash + non-alphanumeric character --> literal symbol (i.e. \.)
    if (*p == '\\') {
      if (!p[1] || isalnum((unsigned char)p[1])) {
        break;
      } else {
        p++;
      }
    }
    pattern_buffer += *p++;
  }
  if (*p == '$') {
    match_end = true;
    p++;
  }
  if (!*p) {
    /* This is an encoding of a literal string. */
    case_insensitive = coptions & PCRE_CASELESS;
    literal_str = std::move(pattern_buffer);
  }
}


int64_t HHVM_FUNCTION(levenshtein,
                      const String& str1,
                      const String& str2,
                      int cost_ins /* = 1 */,
                      int cost_rep /* = 1 */,
                      int cost_del /* = 1 */) {
  return string_levenshtein(str1.data(), str1.size(), str2.data(), str2.size(),
                            cost_ins, cost_rep, cost_del);
}


PregWithErrorGuard::~PregWithErrorGuard() {
  if (*rl_last_error_code == PHP_PCRE_NO_ERROR) {
    error.setNull();
  } else {
    error = *rl_last_error_code;
  }
  *rl_last_error_code = prior_error;
}


  void validateStack(TraceIterator tIt, Stats& stats) {
    auto enteredName = m_stack.back().trace->symbol;
    auto exitedName = tIt->symbol;
    if ((exitedName != nullptr) &&
        ((enteredName == nullptr) || (strcmp(enteredName, exitedName) != 0))) {
      // We have a few special names that we form on entry. We don't
      // have the information to form them again on exit, so tolerate
      // them here. See EventHook::GetFunctionNameForProfiler().
      if ((enteredName != nullptr) &&
          ((strncmp(enteredName, "run_init::", 10) == 0) ||
           (strcmp(enteredName, "_") == 0))) return;
      bool fixed = false;
      if (m_stack.size() > 1) {
        auto callerName = (m_stack.end() - 2)->trace->symbol;
        if ((callerName != nullptr) && (strcmp(callerName, exitedName) == 0)) {
          // We have an exit for Foo(), but we were in Bar(). However,
          // it appears that Foo() was the caller of Bar(). This
          // suggests we've missed the exit event for Bar() and have
          // the exit event for Foo() in hand. So remove Bar() to
          // re-balance the stack.
          m_stack.pop_back();
          fixed = true;
        }
      }
      // The first few bad arcs typically point at the problem, so
      // report them. The rest we'll just count.
      if (++m_badArcCount < 20) {
        std::string badArc;
        if (fixed) {
          badArc = folly::format("(warning: corrected bad arc #{}: "
                                 "enter '{}', exit '{}')",
                                 m_badArcCount,
                                 enteredName, exitedName).str();
        } else {
          badArc = folly::format("(error: bad arc #{}: "
                                 "enter '{}', exit '{}')",
                                 m_badArcCount,
                                 enteredName, exitedName).str();
        }
        ++stats[badArc.data()].count;
      }
    }
  }


_php_image_output_putbuf(struct gdIOCtx* /*ctx*/, const void* buf, int len) {
  return php_write((void *)buf, len);
}


  const char *data() const {
    return m_str ? m_str->data() : "";
  }


Variant str_ireplace(const Variant& search, const Variant& replace,
                     const Variant& subject, int64_t& count) {
  Variant ret = str_replace(search, replace, subject, count, false);
  return ret;
}


explicit Key(EVP_PKEY *key) : m_key(key) { assertx(m_key);}


static inline uint64_t cpuTime(int64_t /*MHz*/) {
  return gettime_ns(CLOCK_THREAD_CPUTIME_ID);
}


explicit StrNR(const String &s) : m_px(s.get()) {} // XXX

String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

static const int npos = -1;

int find(char ch, int pos = 0, bool caseSensitive = true) const;

int find(const char *s, int pos = 0, bool caseSensitive = true) const;

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(char ch, int pos = 0, bool caseSensitive = true) const;

int rfind(const char *s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

friend String&& operator

friend String

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator == (const char* v) const = delete;

bool operator != (const char* v) const = delete;

bool operator >= (const char* v) const = delete;

bool operator <= (const char* v) const = delete;

bool operator >  (const char* v) const = delete;

bool operator <  (const char* v) const = delete;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

bool operator == (const Variant& v) const = delete;

bool operator != (const Variant& v) const = delete;

bool operator >= (const Variant& v) const = delete;

bool operator <= (const Variant& v) const = delete;

bool operator >  (const Variant& v) const = delete;

bool operator <  (const Variant& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;


String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

friend String&& operator

friend String

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;

struct StrNR {
private:
  StringData *m_px;

public:
  StrNR() : m_px(nullptr) {}
  explicit StrNR(StringData *sd) : m_px(sd) {}
  explicit StrNR(const StringData *sd) : m_px(const_cast<StringData*>(sd)) {}
  explicit StrNR(const String &s) : m_px(s.get()) {} // XXX
  explicit StrNR(const char*) = delete;

  ~StrNR() {
    if (debug) {
      m_px = reinterpret_cast<StringData*>(0xdeadbeeffaceb004);
    }
  }

  /* implicit */ operator

inline String& String::operator=(const StaticString& v)


static void _php_image_output_putc(struct gdIOCtx* /*ctx*/, int c) {
  /* without the following downcast, the write will fail
   * (i.e., will write a zero byte) for all
   * big endian architectures:
   */
  unsigned char ch = (unsigned char) c;
  php_write(&ch, 1);
}