diff --git a/lib/onigmo/CMakeLists.txt b/lib/onigmo/CMakeLists.txt index a5f12445591..2591b5b86bc 100644 --- a/lib/onigmo/CMakeLists.txt +++ b/lib/onigmo/CMakeLists.txt @@ -296,6 +296,10 @@ if(ONIGMO_CTESTS) add_executable(test_enc_utf8 test_enc_utf8.c) add_test(NAME test_enc_utf8 COMMAND test_enc_utf8) target_link_libraries(test_enc_utf8 onigmo-static) + + add_executable(test_repeat_id_overflow test_repeat_id_overflow.c) + add_test(NAME test_repeat_id_overflow COMMAND test_repeat_id_overflow) + target_link_libraries(test_repeat_id_overflow onigmo-static) endif() if(ONIGMO_CTESTS_SAMPLE) diff --git a/lib/onigmo/onigmo.h b/lib/onigmo/onigmo.h index aa96a9fe092..ede7cf7014b 100644 --- a/lib/onigmo/onigmo.h +++ b/lib/onigmo/onigmo.h @@ -689,6 +689,8 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax; #define ONIGERR_NEVER_ENDING_RECURSION -221 #define ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY -222 #define ONIGERR_INVALID_CHAR_PROPERTY_NAME -223 +#define ONIGERR_TOO_MANY_RANGE_REPEAT -224 +#define ONIGERR_TOO_MANY_NULL_CHECK -225 #define ONIGERR_INVALID_CODE_POINT_VALUE -400 #define ONIGERR_INVALID_WIDE_CHAR_VALUE -400 #define ONIGERR_TOO_BIG_WIDE_CHAR_VALUE -401 diff --git a/lib/onigmo/regcomp.c b/lib/onigmo/regcomp.c index c8b8943a56d..745a9091e8a 100644 --- a/lib/onigmo/regcomp.c +++ b/lib/onigmo/regcomp.c @@ -374,6 +374,7 @@ compile_tree_empty_check(Node* node, regex_t* reg, int empty_info) r = add_mem_num(reg, reg->num_null_check); /* NULL CHECK ID */ if (r) return r; reg->num_null_check++; + if ((MemNumType)reg->num_null_check <= 0) return ONIGERR_TOO_MANY_NULL_CHECK; } r = compile_tree(node, reg); @@ -686,6 +687,7 @@ compile_range_repeat_node(QtfrNode* qn, int target_len, int empty_info, if (r) return r; r = add_mem_num(reg, num_repeat); /* OP_REPEAT ID */ reg->num_repeat++; + if ((MemNumType)reg->num_repeat <= 0) return ONIGERR_TOO_MANY_RANGE_REPEAT; if (r) return r; r = add_rel_addr(reg, target_len + SIZE_OP_REPEAT_INC); if (r) return r; diff --git a/lib/onigmo/regerror.c b/lib/onigmo/regerror.c index 5569c8b3f3e..c139258d939 100644 --- a/lib/onigmo/regerror.c +++ b/lib/onigmo/regerror.c @@ -177,6 +177,10 @@ onig_error_code_to_format(OnigPosition code) case ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY: p = "group number is too big for capture history"; break; #endif + case ONIGERR_TOO_MANY_RANGE_REPEAT: + p = "too many range repeat"; break; + case ONIGERR_TOO_MANY_NULL_CHECK: + p = "too many null check"; break; case ONIGERR_INVALID_CHAR_PROPERTY_NAME: p = "invalid character property name {%n}"; break; case ONIGERR_TOO_MANY_CAPTURE_GROUPS: diff --git a/lib/onigmo/test_repeat_id_overflow.c b/lib/onigmo/test_repeat_id_overflow.c new file mode 100644 index 00000000000..066ce24e30a --- /dev/null +++ b/lib/onigmo/test_repeat_id_overflow.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include "onigmo.h" + +static int +check_pattern(const char* piece, size_t count, int expected) +{ + size_t piece_len = strlen(piece); + size_t len = piece_len * count; + UChar* pattern = (UChar* )malloc(len + 1); + regex_t* reg = NULL; + OnigErrorInfo error_info; + int result; + size_t i; + + if (pattern == NULL) return 1; + for (i = 0; i < count; i++) + memcpy(pattern + i * piece_len, piece, piece_len); + pattern[len] = '\0'; + + result = onig_new(®, pattern, pattern + len, ONIG_OPTION_DEFAULT, + ONIG_ENCODING_UTF8, ONIG_SYNTAX_RUBY, &error_info); + if (result != expected) + fprintf(stderr, "count=%zu: expected %d, got %d\n", count, expected, result); + + if (reg != NULL) onig_free(reg); + free(pattern); + return result != expected; +} + +int +main(void) +{ + int failed; + + if (onig_init() != ONIG_NORMAL) return 1; + failed = check_pattern("(?:fo){0,100}", 32767, ONIG_NORMAL); + failed |= check_pattern("(?:fo){0,100}", 32768, + ONIGERR_TOO_MANY_RANGE_REPEAT); + failed |= check_pattern("(?:fo){0,100}", 32769, + ONIGERR_TOO_MANY_RANGE_REPEAT); + failed |= check_pattern("(?:a|)*", 40000, + ONIGERR_TOO_MANY_NULL_CHECK); + onig_end(); + return failed; +}