Commit 54ceb286 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 8c246533
...@@ -1047,6 +1047,17 @@ described below. ...@@ -1047,6 +1047,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)) {
...@@ -1674,6 +1685,15 @@ Varnish versions. ...@@ -1674,6 +1685,15 @@ 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
2015-06-01 through 2018-04-01. 2015-06-01 through 2018-04-01.
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.
...@@ -823,6 +823,17 @@ described below. ...@@ -823,6 +823,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)) {
...@@ -1362,6 +1373,15 @@ Varnish versions. ...@@ -1362,6 +1373,15 @@ 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
2015-06-01 through 2018-04-01. 2015-06-01 through 2018-04-01.
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>
...@@ -47,7 +55,8 @@ public: ...@@ -47,7 +55,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;
...@@ -75,7 +84,8 @@ extern "C" { ...@@ -75,7 +84,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