From d430bd2f5cba9d54ac472876e7cd151a53fc031d Mon Sep 17 00:00:00 2001 From: Ruben Gonzalez Date: Mon, 28 May 2018 13:59:43 -0400 Subject: [PATCH] Fix CompileRegex not actually setting a valid error code. (#775) Fix CompileRegex not actually setting a valid error code. --- extensions/regex/CRegEx.cpp | 9 ++- extensions/regex/CRegEx.h | 1 + extensions/regex/extension.cpp | 12 +-- extensions/regex/posix_map.h | 136 +++++++++++++++++++++++++++++++++ plugins/include/regex.inc | 20 ++++- 5 files changed, 169 insertions(+), 9 deletions(-) create mode 100644 extensions/regex/posix_map.h diff --git a/extensions/regex/CRegEx.cpp b/extensions/regex/CRegEx.cpp index 3f57d900..3e3f6a0a 100644 --- a/extensions/regex/CRegEx.cpp +++ b/extensions/regex/CRegEx.cpp @@ -38,6 +38,7 @@ RegEx::RegEx() { mErrorOffset = 0; + mErrorCode = 0; mError = NULL; re = NULL; mFree = true; @@ -48,6 +49,7 @@ RegEx::RegEx() void RegEx::Clear () { mErrorOffset = 0; + mErrorCode = 0; mError = NULL; if (re) pcre_free(re); @@ -80,7 +82,7 @@ int RegEx::Compile(const char *pattern, int iFlags) if (!mFree) Clear(); - re = pcre_compile(pattern, iFlags, &mError, &mErrorOffset, NULL); + re = pcre_compile2(pattern, iFlags, &mErrorCode, &mError, &mErrorOffset, NULL); if (re == NULL) { @@ -115,7 +117,7 @@ int RegEx::Match(const char *str, unsigned int offset) { return 0; } else { - mErrorOffset = rc; + mErrorCode = rc; return -1; } } @@ -158,7 +160,7 @@ int RegEx::MatchAll(const char *str) return 0; } else { - mErrorOffset = rc; + mErrorCode = rc; return -1; } } @@ -172,6 +174,7 @@ void RegEx::ClearMatch() { // Clears match results mErrorOffset = 0; + mErrorCode = 0; mError = NULL; if (subject) delete [] subject; diff --git a/extensions/regex/CRegEx.h b/extensions/regex/CRegEx.h index 99e04e52..66ed1117 100644 --- a/extensions/regex/CRegEx.h +++ b/extensions/regex/CRegEx.h @@ -57,6 +57,7 @@ public: bool GetSubstring(int s, char buffer[], int max, int match); public: int mErrorOffset; + int mErrorCode; const char *mError; int mMatchCount; RegexMatch mMatches[MAX_MATCHES]; diff --git a/extensions/regex/extension.cpp b/extensions/regex/extension.cpp index 975d7eed..c903d96a 100644 --- a/extensions/regex/extension.cpp +++ b/extensions/regex/extension.cpp @@ -33,6 +33,7 @@ #include "extension.h" #include #include "pcre.h" +#include "posix_map.h" #include "CRegEx.h" using namespace SourceHook; @@ -82,10 +83,11 @@ static cell_t CompileRegex(IPluginContext *pCtx, const cell_t *params) if (x->Compile(regex, params[2]) == 0) { - cell_t *eOff; - pCtx->LocalToPhysAddr(params[5], &eOff); + cell_t *eError; + pCtx->LocalToPhysAddr(params[5], &eError); const char *err = x->mError; - *eOff = x->mErrorOffset; + // Convert error code to posix error code but use pcre's error string since it is more detailed. + *eError = pcre_posix_compile_error_map[x->mErrorCode]; pCtx->StringToLocal(params[3], params[4], err ? err:"unknown"); delete x; return 0; @@ -146,7 +148,7 @@ static cell_t MatchRegex(IPluginContext *pCtx, const cell_t *params) /* there was a match error. move on. */ cell_t *res; pCtx->LocalToPhysAddr(params[3], &res); - *res = x->mErrorOffset; + *res = x->mErrorCode; /* only clear the match results, since the regex object may still be referenced later */ x->ClearMatch(); @@ -199,7 +201,7 @@ static cell_t MatchRegexAll(IPluginContext *pCtx, const cell_t *params) /* there was a match error. move on. */ cell_t *res; pCtx->LocalToPhysAddr(params[3], &res); - *res = x->mErrorOffset; + *res = x->mErrorCode; /* only clear the match results, since the regex object may still be referenced later */ x->ClearMatch(); diff --git a/extensions/regex/posix_map.h b/extensions/regex/posix_map.h new file mode 100644 index 00000000..42d36694 --- /dev/null +++ b/extensions/regex/posix_map.h @@ -0,0 +1,136 @@ +#pragma once + +/* + Maps pcre_compile2 error codes to posix error codes. + From pcreposix.c and pcreposix.h +*/ + +// posix error codes +enum { + REG_ASSERT = 1, /* internal error ? */ + REG_BADBR, /* invalid repeat counts in {} */ + REG_BADPAT, /* pattern error */ + REG_BADRPT, /* ? * + invalid */ + REG_EBRACE, /* unbalanced {} */ + REG_EBRACK, /* unbalanced [] */ + REG_ECOLLATE, /* collation error - not relevant */ + REG_ECTYPE, /* bad class */ + REG_EESCAPE, /* bad escape sequence */ + REG_EMPTY, /* empty expression */ + REG_EPAREN, /* unbalanced () */ + REG_ERANGE, /* bad range inside [] */ + REG_ESIZE, /* expression too big */ + REG_ESPACE, /* failed to get memory */ + REG_ESUBREG, /* bad back reference */ + REG_INVARG, /* bad argument */ + + // This isnt used below since it is not a compile error. So we remove it as to not conflict. + //REG_NOMATCH /* match failed */ +}; + +// pcre compile error -> posix compile error +const int pcre_posix_compile_error_map[] = { + 0, /* no error */ + REG_EESCAPE, /* \ at end of pattern */ + REG_EESCAPE, /* \c at end of pattern */ + REG_EESCAPE, /* unrecognized character follows \ */ + REG_BADBR, /* numbers out of order in {} quantifier */ + /* 5 */ + REG_BADBR, /* number too big in {} quantifier */ + REG_EBRACK, /* missing terminating ] for character class */ + REG_ECTYPE, /* invalid escape sequence in character class */ + REG_ERANGE, /* range out of order in character class */ + REG_BADRPT, /* nothing to repeat */ + /* 10 */ + REG_BADRPT, /* operand of unlimited repeat could match the empty string */ + REG_ASSERT, /* internal error: unexpected repeat */ + REG_BADPAT, /* unrecognized character after (? */ + REG_BADPAT, /* POSIX named classes are supported only within a class */ + REG_EPAREN, /* missing ) */ + /* 15 */ + REG_ESUBREG, /* reference to non-existent subpattern */ + REG_INVARG, /* erroffset passed as NULL */ + REG_INVARG, /* unknown option bit(s) set */ + REG_EPAREN, /* missing ) after comment */ + REG_ESIZE, /* parentheses nested too deeply */ + /* 20 */ + REG_ESIZE, /* regular expression too large */ + REG_ESPACE, /* failed to get memory */ + REG_EPAREN, /* unmatched parentheses */ + REG_ASSERT, /* internal error: code overflow */ + REG_BADPAT, /* unrecognized character after (?< */ + /* 25 */ + REG_BADPAT, /* lookbehind assertion is not fixed length */ + REG_BADPAT, /* malformed number or name after (?( */ + REG_BADPAT, /* conditional group contains more than two branches */ + REG_BADPAT, /* assertion expected after (?( */ + REG_BADPAT, /* (?R or (?[+-]digits must be followed by ) */ + /* 30 */ + REG_ECTYPE, /* unknown POSIX class name */ + REG_BADPAT, /* POSIX collating elements are not supported */ + REG_INVARG, /* this version of PCRE is not compiled with PCRE_UTF8 support */ + REG_BADPAT, /* spare error */ + REG_BADPAT, /* character value in \x{} or \o{} is too large */ + /* 35 */ + REG_BADPAT, /* invalid condition (?(0) */ + REG_BADPAT, /* \C not allowed in lookbehind assertion */ + REG_EESCAPE, /* PCRE does not support \L, \l, \N, \U, or \u */ + REG_BADPAT, /* number after (?C is > 255 */ + REG_BADPAT, /* closing ) for (?C expected */ + /* 40 */ + REG_BADPAT, /* recursive call could loop indefinitely */ + REG_BADPAT, /* unrecognized character after (?P */ + REG_BADPAT, /* syntax error in subpattern name (missing terminator) */ + REG_BADPAT, /* two named subpatterns have the same name */ + REG_BADPAT, /* invalid UTF-8 string */ + /* 45 */ + REG_BADPAT, /* support for \P, \p, and \X has not been compiled */ + REG_BADPAT, /* malformed \P or \p sequence */ + REG_BADPAT, /* unknown property name after \P or \p */ + REG_BADPAT, /* subpattern name is too long (maximum 32 characters) */ + REG_BADPAT, /* too many named subpatterns (maximum 10,000) */ + /* 50 */ + REG_BADPAT, /* repeated subpattern is too long */ + REG_BADPAT, /* octal value is greater than \377 (not in UTF-8 mode) */ + REG_BADPAT, /* internal error: overran compiling workspace */ + REG_BADPAT, /* internal error: previously-checked referenced subpattern not found */ + REG_BADPAT, /* DEFINE group contains more than one branch */ + /* 55 */ + REG_BADPAT, /* repeating a DEFINE group is not allowed */ + REG_INVARG, /* inconsistent NEWLINE options */ + REG_BADPAT, /* \g is not followed followed by an (optionally braced) non-zero number */ + REG_BADPAT, /* a numbered reference must not be zero */ + REG_BADPAT, /* an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT) */ + /* 60 */ + REG_BADPAT, /* (*VERB) not recognized */ + REG_BADPAT, /* number is too big */ + REG_BADPAT, /* subpattern name expected */ + REG_BADPAT, /* digit expected after (?+ */ + REG_BADPAT, /* ] is an invalid data character in JavaScript compatibility mode */ + /* 65 */ + REG_BADPAT, /* different names for subpatterns of the same number are not allowed */ + REG_BADPAT, /* (*MARK) must have an argument */ + REG_INVARG, /* this version of PCRE is not compiled with PCRE_UCP support */ + REG_BADPAT, /* \c must be followed by an ASCII character */ + REG_BADPAT, /* \k is not followed by a braced, angle-bracketed, or quoted name */ + /* 70 */ + REG_BADPAT, /* internal error: unknown opcode in find_fixedlength() */ + REG_BADPAT, /* \N is not supported in a class */ + REG_BADPAT, /* too many forward references */ + REG_BADPAT, /* disallowed UTF-8/16/32 code point (>= 0xd800 && <= 0xdfff) */ + REG_BADPAT, /* invalid UTF-16 string (should not occur) */ + /* 75 */ + REG_BADPAT, /* overlong MARK name */ + REG_BADPAT, /* character value in \u.... sequence is too large */ + REG_BADPAT, /* invalid UTF-32 string (should not occur) */ + REG_BADPAT, /* setting UTF is disabled by the application */ + REG_BADPAT, /* non-hex character in \\x{} (closing brace missing?) */ + /* 80 */ + REG_BADPAT, /* non-octal character in \o{} (closing brace missing?) */ + REG_BADPAT, /* missing opening brace after \o */ + REG_BADPAT, /* parentheses too deeply nested */ + REG_BADPAT, /* invalid range in character class */ + REG_BADPAT, /* group name must start with a non-digit */ + /* 85 */ + REG_BADPAT /* parentheses too deeply nested (stack check) */ +}; \ No newline at end of file diff --git a/plugins/include/regex.inc b/plugins/include/regex.inc index 8ebdc4f1..d946659a 100644 --- a/plugins/include/regex.inc +++ b/plugins/include/regex.inc @@ -58,6 +58,24 @@ enum RegexError { REGEX_ERROR_NONE = 0, /* No error */ + + REGEX_ERROR_ASSERT = 1, /* internal error ? */ + REGEX_ERROR_BADBR, /* invalid repeat counts in {} */ + REGEX_ERROR_BADPAT, /* pattern error */ + REGEX_ERROR_BADRPT, /* ? * + invalid */ + REGEX_ERROR_EBRACE, /* unbalanced {} */ + REGEX_ERROR_EBRACK, /* unbalanced [] */ + REGEX_ERROR_ECOLLATE, /* collation error - not relevant */ + REGEX_ERROR_ECTYPE, /* bad class */ + REGEX_ERROR_EESCAPE, /* bad escape sequence */ + REGEX_ERROR_EMPTY, /* empty expression */ + REGEX_ERROR_EPAREN, /* unbalanced () */ + REGEX_ERROR_ERANGE, /* bad range inside [] */ + REGEX_ERROR_ESIZE, /* expression too big */ + REGEX_ERROR_ESPACE, /* failed to get memory */ + REGEX_ERROR_ESUBREG, /* bad back reference */ + REGEX_ERROR_INVARG, /* bad argument */ + REGEX_ERROR_NOMATCH = -1, /* No match was found */ REGEX_ERROR_NULL = -2, REGEX_ERROR_BADOPTION = -3, @@ -124,7 +142,7 @@ methodmap Regex < Handle // @param ret Error code, if applicable. // @return Number of matches found or -1 on failure. // - // @note Use GetSubString() and loop from 1 -> totalmatches. + // @note Use GetSubString() and loop from 0 -> totalmatches - 1. public native int MatchAll(const char[] str, RegexError &ret = REGEX_ERROR_NONE); // Returns a matched substring from a regex handle.