ap_regex: Follow up to r1897240: runtime fallback to alloc/free.

Even though APR_HAS_THREAD_LOCAL is compiled in, ap_regexec() might still be
called by non a apr_thread_t thread, let's fall back to alloc/free in this
case too.



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1897260 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yann Ylavic
2022-01-20 17:01:40 +00:00
parent 0f9cf6fab0
commit 9cda8538a6

View File

@ -281,11 +281,57 @@ typedef int* match_data_pt;
typedef int* match_vector_pt; typedef int* match_vector_pt;
#endif #endif
static APR_INLINE
match_data_pt alloc_match_data(apr_size_t size,
match_vector_pt *ovector,
match_vector_pt small_vector)
{
match_data_pt data;
#ifdef HAVE_PCRE2
data = pcre2_match_data_create(size, NULL);
if (data) {
*ovector = pcre2_get_ovector_pointer(data);
}
#else
if (size > POSIX_MALLOC_THRESHOLD) {
data = malloc(size * sizeof(int) * 3);
}
else {
data = small_vector;
}
*ovector = data;
#endif
return data;
}
static APR_INLINE
void free_match_data(match_data_pt data, apr_size_t size)
{
#ifdef HAVE_PCRE2
pcre2_match_data_free(data);
#else
if (size > POSIX_MALLOC_THRESHOLD) {
free(data);
}
#endif
}
static APR_INLINE
void put_match_data(match_data_pt data, apr_size_t size, int to_free)
{
if (to_free) {
free_match_data(data, size);
}
}
#ifdef APR_HAS_THREAD_LOCAL #ifdef APR_HAS_THREAD_LOCAL
static match_data_pt get_match_data(apr_size_t size, static match_data_pt get_match_data(apr_size_t size,
match_vector_pt *ovector, match_vector_pt *ovector,
match_vector_pt small_vector) match_vector_pt small_vector,
int *to_free)
{ {
apr_thread_t *current; apr_thread_t *current;
struct { struct {
@ -293,9 +339,15 @@ static match_data_pt get_match_data(apr_size_t size,
apr_size_t size; apr_size_t size;
} *tls = NULL; } *tls = NULL;
/* APR_HAS_THREAD_LOCAL garantees this works */ /* Even though APR_HAS_THREAD_LOCAL is compiled in we may still be
current = apr_thread_current(); * called by non a apr_thread_t thread, let's fall back to alloc/free
ap_assert(current != NULL); * in this case.
*/
current = ap_thread_current();
if (!current) {
*to_free = 1;
return alloc_match_data(size, ovector, small_vector);
}
apr_thread_data_get((void **)&tls, "apreg", current); apr_thread_data_get((void **)&tls, "apreg", current);
if (!tls || tls->size < size) { if (!tls || tls->size < size) {
@ -335,49 +387,15 @@ static match_data_pt get_match_data(apr_size_t size,
return tls->data; return tls->data;
} }
/* Nothing to put back with thread local */
static APR_INLINE void put_match_data(match_data_pt data,
apr_size_t size)
{ }
#else /* !APR_HAS_THREAD_LOCAL */ #else /* !APR_HAS_THREAD_LOCAL */
/* Always allocate/free without thread local */ static APR_INLINE match_data_pt get_match_data(apr_size_t size,
match_vector_pt *ovector,
static match_data_pt get_match_data(apr_size_t size, match_vector_pt small_vector,
match_vector_pt *ovector, int *to_free)
match_vector_pt small_vector)
{ {
match_data_pt data; *to_free = 1;
return alloc_match_data(size, ovector, small_vector);
#ifdef HAVE_PCRE2
data = pcre2_match_data_create(size, NULL);
if (data) {
*ovector = pcre2_get_ovector_pointer(data);
}
#else
if (size > POSIX_MALLOC_THRESHOLD) {
data = malloc(size * sizeof(int) * 3);
}
else {
data = small_vector;
}
*ovector = data;
#endif
return data;
}
static APR_INLINE void put_match_data(match_data_pt data,
apr_size_t size)
{
#ifdef HAVE_PCRE2
pcre2_match_data_free(data);
#else
if (size > POSIX_MALLOC_THRESHOLD) {
free(data);
}
#endif
} }
#endif /* !APR_HAS_THREAD_LOCAL */ #endif /* !APR_HAS_THREAD_LOCAL */
@ -395,14 +413,16 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
ap_regmatch_t *pmatch, int eflags) ap_regmatch_t *pmatch, int eflags)
{ {
int rc; int rc;
int options = 0; int options = 0, to_free = 0;
match_vector_pt ovector = NULL; match_vector_pt ovector = NULL;
apr_size_t ncaps = (apr_size_t)preg->re_nsub + 1; apr_size_t ncaps = (apr_size_t)preg->re_nsub + 1;
#if defined(HAVE_PCRE2) || defined(APR_HAS_THREAD_LOCAL) #if defined(HAVE_PCRE2) || defined(APR_HAS_THREAD_LOCAL)
match_data_pt data = get_match_data(ncaps, &ovector, NULL); match_data_pt data = get_match_data(ncaps, &ovector, NULL,
&to_free);
#else #else
int small_vector[POSIX_MALLOC_THRESHOLD * 3]; int small_vector[POSIX_MALLOC_THRESHOLD * 3];
match_data_pt data = get_match_data(ncaps, &ovector, small_vector); match_data_pt data = get_match_data(ncaps, &ovector, small_vector,
&to_free);
#endif #endif
if (!data) { if (!data) {
@ -437,11 +457,11 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
} }
for (; i < nmatch; i++) for (; i < nmatch; i++)
pmatch[i].rm_so = pmatch[i].rm_eo = -1; pmatch[i].rm_so = pmatch[i].rm_eo = -1;
put_match_data(data, ncaps); put_match_data(data, ncaps, to_free);
return 0; return 0;
} }
else { else {
put_match_data(data, ncaps); put_match_data(data, ncaps, to_free);
#ifdef HAVE_PCRE2 #ifdef HAVE_PCRE2
if (rc <= PCRE2_ERROR_UTF8_ERR1 && rc >= PCRE2_ERROR_UTF8_ERR21) if (rc <= PCRE2_ERROR_UTF8_ERR1 && rc >= PCRE2_ERROR_UTF8_ERR21)
return AP_REG_INVARG; return AP_REG_INVARG;