From 440157cbbe796b6b9a44a3de46bbb93d0cb5a77c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 5 Oct 2017 15:01:38 +0200 Subject: [PATCH] MDEV-13412 main.func_regexp_pcre fails in buildbot on ppc64le Caused by 2fcd8c12522. It used the documented pcre API -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0) to calculate the pcre stack frame size. Unfortunately, modern compilers broke it by cloning and inlining pcre match() function. 2fcd8c12522 tried to workaround it by setting the stack frame size to at least 500. It didn't work, 500 is not a universal constant. Now we fix our copy of pcre to not inline or clone match() - so that stack frame detection would work again - and detect at cmake time whether system pcre is broken or usable. Also use stack, not (much slower) malloc in bundled pcre, unless on Windows --- cmake/pcre.cmake | 16 ++++++++++++++-- mysql-test/r/func_regexp_pcre.result | 18 +++++++++--------- mysql-test/t/func_regexp_pcre.test | 8 ++++---- pcre/CMakeLists.txt | 6 +++--- pcre/pcre_exec.c | 6 ++++++ 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/cmake/pcre.cmake b/cmake/pcre.cmake index 894bde38974..4c113929866 100644 --- a/cmake/pcre.cmake +++ b/cmake/pcre.cmake @@ -1,11 +1,23 @@ +INCLUDE (CheckCSourceRuns) + SET(WITH_PCRE "auto" CACHE STRING "Which pcre to use (possible values are 'bundled', 'system', or 'auto')") MACRO (CHECK_PCRE) IF(WITH_PCRE STREQUAL "system" OR WITH_PCRE STREQUAL "auto") - CHECK_LIBRARY_EXISTS(pcre pcre_stack_guard "" HAVE_PCRE) + CHECK_LIBRARY_EXISTS(pcre pcre_stack_guard "" HAVE_PCRE_STACK_GUARD) + IF(NOT CMAKE_CROSSCOMPILING) + SET(CMAKE_REQUIRED_LIBRARIES "pcre") + CHECK_C_SOURCE_RUNS(" + #include + int main() { + return -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0) < 256; + }" PCRE_STACK_SIZE_OK) + SET(CMAKE_REQUIRED_LIBRARIES) + ENDIF() ENDIF() - IF(NOT HAVE_PCRE OR WITH_PCRE STREQUAL "bundled") + IF(NOT HAVE_PCRE_STACK_GUARD OR NOT PCRE_STACK_SIZE_OK OR + WITH_PCRE STREQUAL "bundled") IF (WITH_PCRE STREQUAL "system") MESSAGE(FATAL_ERROR "system pcre is not found or unusable") ENDIF() diff --git a/mysql-test/r/func_regexp_pcre.result b/mysql-test/r/func_regexp_pcre.result index 4089966a7d7..43ea5c23b63 100644 --- a/mysql-test/r/func_regexp_pcre.result +++ b/mysql-test/r/func_regexp_pcre.result @@ -879,32 +879,32 @@ SELECT 1 FROM dual WHERE ('Alpha,Bravo,Charlie,Delta,Echo,Foxtrot,StrataCentral, 1 Warnings: Warning 1139 Got error 'pcre_exec: recursion limit of NUM exceeded' from regexp -SELECT CONCAT(REPEAT('100,',400),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$'; -CONCAT(REPEAT('100,',400),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$' +SELECT CONCAT(REPEAT('100,',250),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$'; +CONCAT(REPEAT('100,',250),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$' 1 SELECT CONCAT(REPEAT('100,',600),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$'; CONCAT(REPEAT('100,',600),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$' 0 Warnings: Warning 1139 Got error 'pcre_exec: recursion limit of NUM exceeded' from regexp -SELECT REGEXP_INSTR(CONCAT(REPEAT('100,',400),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$'); -REGEXP_INSTR(CONCAT(REPEAT('100,',400),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$') +SELECT REGEXP_INSTR(CONCAT(REPEAT('100,',250),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$'); +REGEXP_INSTR(CONCAT(REPEAT('100,',250),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$') 1 SELECT REGEXP_INSTR(CONCAT(REPEAT('100,',600),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$'); REGEXP_INSTR(CONCAT(REPEAT('100,',600),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$') 0 Warnings: Warning 1139 Got error 'pcre_exec: recursion limit of NUM exceeded' from regexp -SELECT LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',400/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')); -LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',400/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')) -535 +SELECT LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',250/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')); +LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',250/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')) +335 SELECT LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',600/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')); LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',600/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')) 0 Warnings: Warning 1139 Got error 'pcre_exec: recursion limit of NUM exceeded' from regexp -SELECT LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',400/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')); -LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',400/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')) +SELECT LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',250/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')); +LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',250/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')) 0 SELECT LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',600/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')); LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',600/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')) diff --git a/mysql-test/t/func_regexp_pcre.test b/mysql-test/t/func_regexp_pcre.test index 07de4b33271..377ee1a3f02 100644 --- a/mysql-test/t/func_regexp_pcre.test +++ b/mysql-test/t/func_regexp_pcre.test @@ -434,18 +434,18 @@ SELECT 1 FROM dual WHERE ('Alpha,Bravo,Charlie,Delta,Echo,Foxtrot,StrataCentral, # # MDEV-13173 An RLIKE that previously worked on 10.0 now returns "Got error 'pcre_exec: recursion limit of 100 exceeded' from regexp" # -SELECT CONCAT(REPEAT('100,',400),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$'; +SELECT CONCAT(REPEAT('100,',250),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$'; --replace_regex /[0-9]+ exceeded/NUM exceeded/ SELECT CONCAT(REPEAT('100,',600),'101') RLIKE '^(([1-9][0-9]*),)*[1-9][0-9]*$'; -SELECT REGEXP_INSTR(CONCAT(REPEAT('100,',400),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$'); +SELECT REGEXP_INSTR(CONCAT(REPEAT('100,',250),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$'); --replace_regex /[0-9]+ exceeded/NUM exceeded/ SELECT REGEXP_INSTR(CONCAT(REPEAT('100,',600),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$'); -SELECT LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',400/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')); +SELECT LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',250/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')); --replace_regex /[0-9]+ exceeded/NUM exceeded/ SELECT LENGTH(REGEXP_SUBSTR(CONCAT(REPEAT('100,',600/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$')); -SELECT LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',400/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')); +SELECT LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',250/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')); --replace_regex /[0-9]+ exceeded/NUM exceeded/ SELECT LENGTH(REGEXP_REPLACE(CONCAT(REPEAT('100,',600/3),'101'), '^(([1-9][0-9]*),)*[1-9][0-9]*$', '')); diff --git a/pcre/CMakeLists.txt b/pcre/CMakeLists.txt index 30b06a46fef..31d4358f14d 100644 --- a/pcre/CMakeLists.txt +++ b/pcre/CMakeLists.txt @@ -128,9 +128,9 @@ SET(PCREGREP_BUFSIZE "20480" CACHE STRING SET(PCRE_NEWLINE "LF" CACHE STRING "What to recognize as a newline (one of CR, LF, CRLF, ANY, ANYCRLF).") -# MARIADB: Changed the default from OFF to ON as pcre_test.bat on Windows -# MARIADB: fails complaining about too small stack size on Windows. -SET(PCRE_NO_RECURSE ON CACHE BOOL +# Windows has much smaller stack (pcre recursion limit of 112, vs +# 250-500 on Linuxes) +SET(PCRE_NO_RECURSE "${WIN32}" CACHE BOOL "If ON, then don't use stack recursion when matching. See NO_RECURSE in config.h.in for details.") SET(PCRE_POSIX_MALLOC_THRESHOLD "10" CACHE STRING diff --git a/pcre/pcre_exec.c b/pcre/pcre_exec.c index 70ac2fea381..fa84d924a4c 100644 --- a/pcre/pcre_exec.c +++ b/pcre/pcre_exec.c @@ -509,6 +509,12 @@ Returns: MATCH_MATCH if matched ) these values are >= 0 (e.g. stopped by repeated call or recursion limit) */ +#ifdef __GNUC__ +static int +match(REGISTER PCRE_PUCHAR eptr, REGISTER const pcre_uchar *ecode, + PCRE_PUCHAR mstart, int offset_top, match_data *md, eptrblock *eptrb, + unsigned int rdepth) __attribute__((noinline,noclone)); +#endif static int match(REGISTER PCRE_PUCHAR eptr, REGISTER const pcre_uchar *ecode, PCRE_PUCHAR mstart, int offset_top, match_data *md, eptrblock *eptrb,