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.
``.match()`` MUST be called after ``.compile()``; otherwise the match
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::
if (hostmatcher.match(req.http.Host)) {
......@@ -1670,6 +1681,15 @@ compatible with other Varnish 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).
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
============
......
......@@ -70,6 +70,28 @@ AC_FUNC_REALLOC
AC_FUNC_ERROR_AT_LINE
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
AC_ARG_ENABLE(stack-protector,
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)
char *buf;
size_t buflen;
const char *err;
errorkind_e errkind = NO_ERROR;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_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)
buf = WS_Front(ctx->ws);
buflen = WS_Reserve(ctx->ws, 0);
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);
WS_Release(ctx->ws, 0);
return 0;
......@@ -376,8 +377,25 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
task->matches = (int *)buf;
WS_Release(ctx->ws, task->nmatches * sizeof(int));
}
else
else {
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;
}
......
This diff is collapsed.
......@@ -821,6 +821,17 @@ described below.
``.match()`` MUST be called after ``.compile()``; otherwise the match
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::
if (hostmatcher.match(req.http.Host)) {
......@@ -1360,6 +1371,15 @@ compatible with other Varnish 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).
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
============
......
......@@ -27,6 +27,8 @@
*
*/
#include "config.h"
#include <algorithm>
#include "vre2set.h"
......@@ -70,9 +72,19 @@ vre2set::compile() const
}
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);
#endif
}
const char *
......@@ -148,13 +160,14 @@ vre2set_compile(vre2set *set)
const char *
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 {
vector<int> m;
*nmatches = 0;
*match = set->match(subject, &m);
*match = set->match(subject, &m, err);
if (*match) {
if (m.size() * sizeof(int) > buflen)
return "insufficient space to copy match data";
......
......@@ -30,6 +30,14 @@
#ifndef _VRE2SET_H
#define _VRE2SET_H
typedef enum {
NO_ERROR = 0,
NOT_COMPILED,
OUT_OF_MEMORY,
INCONSISTENT,
NOT_IMPLEMENTED
} errorkind_e;
#ifdef __cplusplus
#include <re2/re2.h>
......@@ -46,7 +54,8 @@ public:
virtual ~vre2set();
int add(const char* pattern, string* error) 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
typedef struct vre2set vre2set;
......@@ -74,7 +83,8 @@ extern "C" {
const char *vre2set_compile(vre2set *set);
const char *vre2set_match(vre2set *set, const char *subject,
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
}
......
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