summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/util_pcre.c165
1 files changed, 64 insertions, 101 deletions
diff --git a/server/util_pcre.c b/server/util_pcre.c
index 2be99842c1..463c8c7256 100644
--- a/server/util_pcre.c
+++ b/server/util_pcre.c
@@ -74,8 +74,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define APR_WANT_STRFUNC
#include "apr_want.h"
-#ifndef POSIX_MALLOC_THRESHOLD
-#define POSIX_MALLOC_THRESHOLD (10)
+#ifndef AP_PCRE_STACKBUF_SIZE
+#define AP_PCRE_STACKBUF_SIZE (256)
#endif
/* Table of error strings corresponding to POSIX error codes; must be
@@ -281,117 +281,85 @@ typedef int* match_data_pt;
typedef int* match_vector_pt;
#endif
-static APR_INLINE
-match_data_pt alloc_match_data(apr_size_t size,
- match_vector_pt small_vector)
+struct match_data_state
{
match_data_pt data;
-
+ char *buf;
+ apr_size_t buf_len;
+ apr_size_t buf_used;
#ifdef HAVE_PCRE2
- data = pcre2_match_data_create(size, NULL);
-#else
- if (size > POSIX_MALLOC_THRESHOLD) {
- data = malloc(size * sizeof(int) * 3);
- }
- else {
- data = small_vector;
- }
+ pcre2_general_context *pcre2_ctx;
#endif
+};
- return data;
-}
-
-static APR_INLINE
-void free_match_data(match_data_pt data, apr_size_t size)
+static void * private_malloc(size_t size, void *ctx)
{
-#ifdef HAVE_PCRE2
- pcre2_match_data_free(data);
-#else
- if (size > POSIX_MALLOC_THRESHOLD) {
- free(data);
- }
-#endif
-}
+ struct match_data_state *state = ctx;
-#if AP_HAS_THREAD_LOCAL && !defined(APREG_NO_THREAD_LOCAL)
+ if(size <= (state->buf_len - state->buf_used)) {
+ void *p = state->buf + state->buf_used;
-struct apreg_tls {
- match_data_pt data;
- apr_size_t size;
-};
+ state->buf_used += APR_ALIGN_DEFAULT(size);
-#ifdef HAVE_PCRE2
-static apr_status_t apreg_tls_cleanup(void *arg)
-{
- struct apreg_tls *tls = arg;
- pcre2_match_data_free(tls->data); /* NULL safe */
- return APR_SUCCESS;
+ return p;
+ }
+ else {
+ return malloc(size);
+ }
}
-#endif
-static match_data_pt get_match_data(apr_size_t size,
- match_vector_pt small_vector,
- int *to_free)
+static void private_free(void *block, void *ctx)
{
- apr_thread_t *current;
- struct apreg_tls *tls = NULL;
-
- /* Even though AP_HAS_THREAD_LOCAL, we may still be called by a
- * native/non-apr thread, let's fall back to alloc/free in this case.
- */
- current = ap_thread_current();
- if (!current) {
- *to_free = 1;
- return alloc_match_data(size, small_vector);
- }
+ struct match_data_state *state = ctx;
+ void *buf_start = state->buf;
+ void *buf_end = state->buf + state->buf_len;
- apr_thread_data_get((void **)&tls, "apreg", current);
- if (!tls || tls->size < size) {
- apr_pool_t *tp = apr_thread_pool_get(current);
- if (!tls) {
- tls = apr_pcalloc(tp, sizeof(*tls));
-#ifdef HAVE_PCRE2
- apr_thread_data_set(tls, "apreg", apreg_tls_cleanup, current);
-#else
- apr_thread_data_set(tls, "apreg", NULL, current);
-#endif
- }
+ if (block >= buf_start && block <= buf_end) {
+ /* This block allocated from stack buffer. Do nothing. */
+ }
+ else {
+ free(block);
+ }
+}
- tls->size *= 2;
- if (tls->size < size) {
- tls->size = size;
- if (tls->size < POSIX_MALLOC_THRESHOLD) {
- tls->size = POSIX_MALLOC_THRESHOLD;
- }
- }
+static APR_INLINE
+match_data_pt alloc_match_data(apr_size_t size,
+ struct match_data_state *state,
+ void *stack_buf,
+ apr_size_t stack_buf_len)
+{
+ state->buf = stack_buf;
+ state->buf_len = stack_buf_len;
+ state->buf_used = 0;
#ifdef HAVE_PCRE2
- pcre2_match_data_free(tls->data); /* NULL safe */
- tls->data = pcre2_match_data_create(tls->size, NULL);
- if (!tls->data) {
- tls->size = 0;
- return NULL;
- }
+ state->pcre2_ctx = pcre2_general_context_create(private_malloc, private_free, state);
+ if (!state->pcre2_ctx) {
+ return NULL;
+ }
+ state->data = pcre2_match_data_create((int)size, state->pcre2_ctx);
+ if (!state->data) {
+ pcre2_general_context_free(state->pcre2_ctx);
+ return NULL;
+ }
#else
- tls->data = apr_palloc(tp, tls->size * sizeof(int) * 3);
+ state->data = private_malloc(size * sizeof(int) * 3, state);
#endif
- }
- return tls->data;
+ return state->data;
}
-#else /* AP_HAS_THREAD_LOCAL && !defined(APREG_NO_THREAD_LOCAL) */
-
-static APR_INLINE match_data_pt get_match_data(apr_size_t size,
- match_vector_pt small_vector,
- int *to_free)
+static APR_INLINE
+void free_match_data(struct match_data_state *state)
{
- *to_free = 1;
- return alloc_match_data(size, small_vector);
+#ifdef HAVE_PCRE2
+ pcre2_match_data_free(state->data);
+ pcre2_general_context_free(state->pcre2_ctx);
+#else
+ private_free(state->data, state);
+#endif
}
-#endif /* AP_HAS_THREAD_LOCAL && !defined(APREG_NO_THREAD_LOCAL) */
-
AP_DECLARE(int) ap_regexec(const ap_regex_t *preg, const char *string,
apr_size_t nmatch, ap_regmatch_t *pmatch,
int eflags)
@@ -408,13 +376,12 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
int options = 0, to_free = 0;
match_vector_pt ovector = NULL;
apr_size_t ncaps = (apr_size_t)preg->re_nsub + 1;
-#ifdef HAVE_PCRE2
- match_data_pt data = get_match_data(ncaps, NULL, &to_free);
-#else
- int small_vector[POSIX_MALLOC_THRESHOLD * 3];
- match_data_pt data = get_match_data(ncaps, small_vector, &to_free);
-#endif
+ struct match_data_state state;
+ match_data_pt data;
+ /* Use apr_uint64_t to get proper alignment. */
+ apr_uint64_t stack_buf[(AP_PCRE_STACKBUF_SIZE + sizeof(apr_uint64_t) - 1) / sizeof(apr_uint64_t)];
+ data = alloc_match_data(ncaps, &state, stack_buf, sizeof(stack_buf));
if (!data) {
return AP_REG_ESPACE;
}
@@ -449,15 +416,11 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
}
for (; i < nmatch; i++)
pmatch[i].rm_so = pmatch[i].rm_eo = -1;
- if (to_free) {
- free_match_data(data, ncaps);
- }
+ free_match_data(&state);
return 0;
}
else {
- if (to_free) {
- free_match_data(data, ncaps);
- }
+ free_match_data(&state);
#ifdef HAVE_PCRE2
if (rc <= PCRE2_ERROR_UTF8_ERR1 && rc >= PCRE2_ERROR_UTF8_ERR21)
return AP_REG_INVARG;