Commit 802506c4 authored by Geoff Simmons's avatar Geoff Simmons

Use the Set::Match() version with ErrorInfo from RE2, if available.

If RE2 reports the "DFA out-of-memory" condition for a failed set
match, the VMOD reports the error as well.
parent f1241cf8
...@@ -1043,6 +1043,17 @@ described below. ...@@ -1043,6 +1043,17 @@ described below.
``.match()`` MUST be called after ``.compile()``; otherwise the match ``.match()`` MUST be called after ``.compile()``; otherwise the match
always fails. always fails.
A match may also fail (returning ``false``) if the internal memory
limit imposed by the ``max_mem`` parameter in the constructor is
exceeded. (With the default value of ``max_mem``, this ordinarily
requires very large patterns and/or a very large string to be
matched.) Since about version 2017-12-01, the RE2 library reports
this condition; if so, the VMOD writes a ``VCL_Error`` message in the
log if it happens, except during ``vcl_init``, in which case the VCL
load fails with the error message. If matches fail due to the
out-of-memory condition, increase the ``max_mem`` parameter in the
constructor.
Example:: Example::
if (hostmatcher.match(req.http.Host)) { if (hostmatcher.match(req.http.Host)) {
...@@ -1670,6 +1681,15 @@ compatible with other Varnish versions. ...@@ -1670,6 +1681,15 @@ compatible with other Varnish versions.
It requires the RE2 library, and has been tested against RE2 versions It requires the RE2 library, and has been tested against RE2 versions
since 2015-06-01 (through 2018-04-01 at the time of writing). since 2015-06-01 (through 2018-04-01 at the time of writing).
If the VMOD is built against versions of RE2 since 2017-12-01, it uses
a version of the set match operation that reports out-of-memory
conditions during a match. In that case, the VMOD is not compatible
with earlier versions of RE2. This is only a problem if the runtime
version of the library differs from the version against which the VMOD
was built. If you encounter this error, consider re-building the VMOD
against the runtime version of RE2, or installing a newer version of
RE2.
INSTALLATION INSTALLATION
============ ============
......
...@@ -70,6 +70,28 @@ AC_FUNC_REALLOC ...@@ -70,6 +70,28 @@ AC_FUNC_REALLOC
AC_FUNC_ERROR_AT_LINE AC_FUNC_ERROR_AT_LINE
AC_CHECK_HEADER_STDBOOL AC_CHECK_HEADER_STDBOOL
# Check if the Set::Match() method supports error reporting, to notify
# if a match failed due to the DFA hitting the max_mem
# limit. Available since RE2 commit ee52f03, or since version
# 2017-12-01.
AC_LANG(C++)
SAVE_CXXFLAGS="$CXXFLAGS"
CXXFLAGS+=" -std=c++11"
AC_MSG_CHECKING([for RE2::Set::Match() with ErrorInfo])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <re2/set.h>]], [[
re2::RE2::Set s(re2::RE2::DefaultOptions, re2::RE2::UNANCHORED);
s.Match("", NULL, NULL)]])],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_SET_MATCH_ERRORINFO], [1],
[Define to 1 if RE2::Set::Match() has the ErrorInfo parameter])
],
[AC_MSG_RESULT([no])
AC_DEFINE([HAVE_SET_MATCH_ERRORINFO], [0],
[Define to 1 if RE2::Set::Match() has the ErrorInfo parameter])
])
CXXFLAGS="$SAVE_CXXFLAGS"
AC_LANG(C)
# --enable-stack-protector # --enable-stack-protector
AC_ARG_ENABLE(stack-protector, AC_ARG_ENABLE(stack-protector,
AS_HELP_STRING([--enable-stack-protector],[enable stack protector (default is YES)]), AS_HELP_STRING([--enable-stack-protector],[enable stack protector (default is YES)]),
......
...@@ -334,6 +334,7 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject) ...@@ -334,6 +334,7 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
char *buf; char *buf;
size_t buflen; size_t buflen;
const char *err; const char *err;
errorkind_e errkind = NO_ERROR;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
...@@ -367,7 +368,7 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject) ...@@ -367,7 +368,7 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
buf = WS_Front(ctx->ws); buf = WS_Front(ctx->ws);
buflen = WS_Reserve(ctx->ws, 0); buflen = WS_Reserve(ctx->ws, 0);
if ((err = vre2set_match(set->set, subject, &match, buf, buflen, if ((err = vre2set_match(set->set, subject, &match, buf, buflen,
&task->nmatches)) != NULL) { &task->nmatches, &errkind)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err); VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err);
WS_Release(ctx->ws, 0); WS_Release(ctx->ws, 0);
return 0; return 0;
...@@ -376,8 +377,25 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject) ...@@ -376,8 +377,25 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
task->matches = (int *)buf; task->matches = (int *)buf;
WS_Release(ctx->ws, task->nmatches * sizeof(int)); WS_Release(ctx->ws, task->nmatches * sizeof(int));
} }
else else {
WS_Release(ctx->ws, 0); WS_Release(ctx->ws, 0);
switch(errkind) {
case NO_ERROR:
case NOT_IMPLEMENTED:
break;
case OUT_OF_MEMORY:
VERR(ctx, ERR_PREFIX "RE2 lib indicates out-of-memory "
"during match, consider increasing max_mem",
set->vcl_name, subject);
break;
case NOT_COMPILED:
case INCONSISTENT:
default:
WRONG("impossible or invalid error kind");
}
}
return match; return match;
} }
......
This diff is collapsed.
...@@ -821,6 +821,17 @@ described below. ...@@ -821,6 +821,17 @@ described below.
``.match()`` MUST be called after ``.compile()``; otherwise the match ``.match()`` MUST be called after ``.compile()``; otherwise the match
always fails. always fails.
A match may also fail (returning ``false``) if the internal memory
limit imposed by the ``max_mem`` parameter in the constructor is
exceeded. (With the default value of ``max_mem``, this ordinarily
requires very large patterns and/or a very large string to be
matched.) Since about version 2017-12-01, the RE2 library reports
this condition; if so, the VMOD writes a ``VCL_Error`` message in the
log if it happens, except during ``vcl_init``, in which case the VCL
load fails with the error message. If matches fail due to the
out-of-memory condition, increase the ``max_mem`` parameter in the
constructor.
Example:: Example::
if (hostmatcher.match(req.http.Host)) { if (hostmatcher.match(req.http.Host)) {
...@@ -1360,6 +1371,15 @@ compatible with other Varnish versions. ...@@ -1360,6 +1371,15 @@ compatible with other Varnish versions.
It requires the RE2 library, and has been tested against RE2 versions It requires the RE2 library, and has been tested against RE2 versions
since 2015-06-01 (through 2018-04-01 at the time of writing). since 2015-06-01 (through 2018-04-01 at the time of writing).
If the VMOD is built against versions of RE2 since 2017-12-01, it uses
a version of the set match operation that reports out-of-memory
conditions during a match. In that case, the VMOD is not compatible
with earlier versions of RE2. This is only a problem if the runtime
version of the library differs from the version against which the VMOD
was built. If you encounter this error, consider re-building the VMOD
against the runtime version of RE2, or installing a newer version of
RE2.
INSTALLATION INSTALLATION
============ ============
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
* *
*/ */
#include "config.h"
#include <algorithm> #include <algorithm>
#include "vre2set.h" #include "vre2set.h"
...@@ -70,9 +72,19 @@ vre2set::compile() const ...@@ -70,9 +72,19 @@ vre2set::compile() const
} }
inline bool inline bool
vre2set::match(const char* subject, vector<int>* m) const vre2set::match(const char* subject, vector<int>* m, errorkind_e* err) const
{ {
#if HAVE_SET_MATCH_ERRORINFO
bool ret;
RE2::Set::ErrorInfo errinfo;
ret = set_->Match(subject, m, &errinfo);
*err = (errorkind_e) errinfo.kind;
return ret;
#else
*err = NOT_IMPLEMENTED;
return set_->Match(subject, m); return set_->Match(subject, m);
#endif
} }
const char * const char *
...@@ -148,13 +160,14 @@ vre2set_compile(vre2set *set) ...@@ -148,13 +160,14 @@ vre2set_compile(vre2set *set)
const char * const char *
vre2set_match(vre2set *set, const char * const subject, int * const match, vre2set_match(vre2set *set, const char * const subject, int * const match,
void *buf, const size_t buflen, size_t * const nmatches) void *buf, const size_t buflen, size_t * const nmatches,
errorkind_e * const err)
{ {
try { try {
vector<int> m; vector<int> m;
*nmatches = 0; *nmatches = 0;
*match = set->match(subject, &m); *match = set->match(subject, &m, err);
if (*match) { if (*match) {
if (m.size() * sizeof(int) > buflen) if (m.size() * sizeof(int) > buflen)
return "insufficient space to copy match data"; return "insufficient space to copy match data";
......
...@@ -30,6 +30,14 @@ ...@@ -30,6 +30,14 @@
#ifndef _VRE2SET_H #ifndef _VRE2SET_H
#define _VRE2SET_H #define _VRE2SET_H
typedef enum {
NO_ERROR = 0,
NOT_COMPILED,
OUT_OF_MEMORY,
INCONSISTENT,
NOT_IMPLEMENTED
} errorkind_e;
#ifdef __cplusplus #ifdef __cplusplus
#include <re2/re2.h> #include <re2/re2.h>
...@@ -46,7 +54,8 @@ public: ...@@ -46,7 +54,8 @@ public:
virtual ~vre2set(); virtual ~vre2set();
int add(const char* pattern, string* error) const; int add(const char* pattern, string* error) const;
bool compile() const; bool compile() const;
bool match(const char* subject, std::vector<int>* m) const; bool match(const char* subject, std::vector<int>* m,
errorkind_e* err) const;
}; };
#else #else
typedef struct vre2set vre2set; typedef struct vre2set vre2set;
...@@ -74,7 +83,8 @@ extern "C" { ...@@ -74,7 +83,8 @@ extern "C" {
const char *vre2set_compile(vre2set *set); const char *vre2set_compile(vre2set *set);
const char *vre2set_match(vre2set *set, const char *subject, const char *vre2set_match(vre2set *set, const char *subject,
int * const match, void *buf, int * const match, void *buf,
const size_t buflen, size_t * const nmatches); const size_t buflen, size_t * const nmatches,
errorkind_e * const err);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment