facebook/hhvm — pull request #4042 by tstarling (2014-10-23 04:03:24+00:00)
Title: Fix PCRE cache, and related code cleanup

When the PCRE cache fills up, memory is leaked since the static string created by insert_cached_pcre() cannot be freed. Also, queueing cached
regexes for deletion on request termination is not good policy -- it is effectively a memory leak for long-running scripts.

Also, when the PCRE cache is full, new regexes need to be recompiled on
every call to preg_match() etc. so the performance of an app using
dynamically-generated regex strings will degrade once the limit is
reached.

So:
* Introduce a thread-local PCRE cache with LRU eviction, used alongside
the existing cache.
* Do not place an entry in the shared cache unless the input text is a
static string. This prevents pollution of the shared cache with
regexes derived from user input.
* If the shared cache is full, or if the regex text is non-static, store
the pcre object in the local cache.
* Use reference counting for local cache entries so that recursive code
which requires more than 1024 regexes to be active at a given time
will not crash. But for entries in the shared cache, do not update the
reference count, to avoid degrading performance due bus activity.
* Retain the thread-local cache beyond the end of the request. This is
basically the same as the way Zend manages its PCRE cache, and should
reduce startup overhead.
* Remove m_overflow and associated functions.
* Make the "bump" regex a static string so that its regex will be
shared.

Also:
* Use tl_ prefix for thread-local variables, per convention.
* Fix a race condition in get_subpat_names() which would have caused
occasional incorrect match results and memory leakage. Build the array
in a temporary variable and then atomically swap it in to the shared
entry, instead of overwriting the shared pointer and then
progressively building the array while the cache is in a broken state.
* Note that "const pcre_cache_entry*" becomes non-const
pcre_cache_entry_ptr in a few places, since "const SmartPtr" would be
equivalent to "pcre_cache_entry const*". There's no equivalent for
a non-const SmartPtr which wraps a const.