Skip to content

Commit 5b597a2

Browse files
committed
Fix bug #72402: _php_mb_regex_ereg_replace_exec - double free
1 parent e9ac895 commit 5b597a2

File tree

2 files changed

+49
-33
lines changed

2 files changed

+49
-33
lines changed

ext/mbstring/php_mbregex.c

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include "ext/standard/info.h"
3333
#include "php_mbregex.h"
3434
#include "mbstring.h"
35-
35+
3636
#include "php_onig_compat.h" /* must come prior to the oniguruma header */
3737
#include <oniguruma.h>
3838
#undef UChar
@@ -55,7 +55,7 @@ struct _zend_mb_regex_globals {
5555
#define MBREX(g) (MBSTRG(mb_regex_globals)->g)
5656

5757
/* {{{ static void php_mb_regex_free_cache() */
58-
static void php_mb_regex_free_cache(php_mb_regex_t **pre)
58+
static void php_mb_regex_free_cache(php_mb_regex_t **pre)
5959
{
6060
onig_free(*pre);
6161
}
@@ -78,7 +78,7 @@ static int _php_mb_regex_globals_ctor(zend_mb_regex_globals *pglobals TSRMLS_DC)
7878
/* }}} */
7979

8080
/* {{{ _php_mb_regex_globals_dtor */
81-
static void _php_mb_regex_globals_dtor(zend_mb_regex_globals *pglobals TSRMLS_DC)
81+
static void _php_mb_regex_globals_dtor(zend_mb_regex_globals *pglobals TSRMLS_DC)
8282
{
8383
zend_hash_destroy(&pglobals->ht_rc);
8484
}
@@ -466,7 +466,7 @@ static php_mb_regex_t *php_mbregex_compile_pattern(const char *pattern, int patl
466466
retval = *rc;
467467
}
468468
out:
469-
return retval;
469+
return retval;
470470
}
471471
/* }}} */
472472

@@ -483,15 +483,15 @@ static size_t _php_mb_regex_get_option_string(char *str, size_t len, OnigOptionT
483483
--len_left;
484484
*(p++) = 'i';
485485
}
486-
++len_req;
486+
++len_req;
487487
}
488488

489489
if ((option & ONIG_OPTION_EXTEND) != 0) {
490490
if (len_left > 0) {
491491
--len_left;
492492
*(p++) = 'x';
493493
}
494-
++len_req;
494+
++len_req;
495495
}
496496

497497
if ((option & (ONIG_OPTION_MULTILINE | ONIG_OPTION_SINGLELINE)) ==
@@ -500,37 +500,37 @@ static size_t _php_mb_regex_get_option_string(char *str, size_t len, OnigOptionT
500500
--len_left;
501501
*(p++) = 'p';
502502
}
503-
++len_req;
503+
++len_req;
504504
} else {
505505
if ((option & ONIG_OPTION_MULTILINE) != 0) {
506506
if (len_left > 0) {
507507
--len_left;
508508
*(p++) = 'm';
509509
}
510-
++len_req;
510+
++len_req;
511511
}
512512

513513
if ((option & ONIG_OPTION_SINGLELINE) != 0) {
514514
if (len_left > 0) {
515515
--len_left;
516516
*(p++) = 's';
517517
}
518-
++len_req;
518+
++len_req;
519519
}
520-
}
520+
}
521521
if ((option & ONIG_OPTION_FIND_LONGEST) != 0) {
522522
if (len_left > 0) {
523523
--len_left;
524524
*(p++) = 'l';
525525
}
526-
++len_req;
526+
++len_req;
527527
}
528528
if ((option & ONIG_OPTION_FIND_NOT_EMPTY) != 0) {
529529
if (len_left > 0) {
530530
--len_left;
531531
*(p++) = 'n';
532532
}
533-
++len_req;
533+
++len_req;
534534
}
535535

536536
c = 0;
@@ -566,7 +566,7 @@ static size_t _php_mb_regex_get_option_string(char *str, size_t len, OnigOptionT
566566
--len_left;
567567
*(p++) = '\0';
568568
}
569-
++len_req;
569+
++len_req;
570570
if (len < len_req) {
571571
return len_req;
572572
}
@@ -577,11 +577,11 @@ static size_t _php_mb_regex_get_option_string(char *str, size_t len, OnigOptionT
577577

578578
/* {{{ _php_mb_regex_init_options */
579579
static void
580-
_php_mb_regex_init_options(const char *parg, int narg, OnigOptionType *option, OnigSyntaxType **syntax, int *eval)
580+
_php_mb_regex_init_options(const char *parg, int narg, OnigOptionType *option, OnigSyntaxType **syntax, int *eval)
581581
{
582582
int n;
583583
char c;
584-
int optm = 0;
584+
int optm = 0;
585585

586586
*syntax = ONIG_SYNTAX_RUBY;
587587

@@ -636,13 +636,13 @@ _php_mb_regex_init_options(const char *parg, int narg, OnigOptionType *option, O
636636
*syntax = ONIG_SYNTAX_POSIX_EXTENDED;
637637
break;
638638
case 'e':
639-
if (eval != NULL) *eval = 1;
639+
if (eval != NULL) *eval = 1;
640640
break;
641641
default:
642642
break;
643643
}
644644
}
645-
if (option != NULL) *option|=optm;
645+
if (option != NULL) *option|=optm;
646646
}
647647
}
648648
/* }}} */
@@ -860,11 +860,11 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
860860
} else {
861861
/* FIXME: this code is not multibyte aware! */
862862
convert_to_long_ex(arg_pattern_zval);
863-
pat_buf[0] = (char)Z_LVAL_PP(arg_pattern_zval);
863+
pat_buf[0] = (char)Z_LVAL_PP(arg_pattern_zval);
864864
pat_buf[1] = '\0';
865865

866866
arg_pattern = pat_buf;
867-
arg_pattern_len = 1;
867+
arg_pattern_len = 1;
868868
}
869869
/* create regex pattern buffer */
870870
re = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, options, MBREX(current_mbctype), syntax TSRMLS_CC);
@@ -934,7 +934,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
934934
}
935935
}
936936
}
937-
937+
938938
if (eval) {
939939
zval v;
940940
/* null terminate buffer */
@@ -953,32 +953,31 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
953953
eval_buf.len = 0;
954954
zval_dtor(&v);
955955
} else if (is_callable) {
956-
zval *retval_ptr;
956+
zval *retval_ptr = NULL;
957957
zval **args[1];
958958
zval *subpats;
959959
int i;
960-
960+
961961
MAKE_STD_ZVAL(subpats);
962962
array_init(subpats);
963-
963+
964964
for (i = 0; i < regs->num_regs; i++) {
965965
add_next_index_stringl(subpats, string + regs->beg[i], regs->end[i] - regs->beg[i], 1);
966-
}
967-
966+
}
967+
968968
args[0] = &subpats;
969969
/* null terminate buffer */
970970
smart_str_0(&eval_buf);
971-
971+
972972
arg_replace_fci.param_count = 1;
973973
arg_replace_fci.params = args;
974974
arg_replace_fci.retval_ptr_ptr = &retval_ptr;
975-
if (zend_call_function(&arg_replace_fci, &arg_replace_fci_cache TSRMLS_CC) == SUCCESS && arg_replace_fci.retval_ptr_ptr) {
975+
if (zend_call_function(&arg_replace_fci, &arg_replace_fci_cache TSRMLS_CC) == SUCCESS && arg_replace_fci.retval_ptr_ptr && retval_ptr) {
976976
convert_to_string_ex(&retval_ptr);
977977
smart_str_appendl(&out_buf, Z_STRVAL_P(retval_ptr), Z_STRLEN_P(retval_ptr));
978978
eval_buf.len = 0;
979979
zval_ptr_dtor(&retval_ptr);
980980
} else {
981-
efree(description);
982981
if (!EG(exception)) {
983982
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call custom replacement function");
984983
}
@@ -991,7 +990,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
991990
pos = (OnigUChar *)string + n;
992991
} else {
993992
if (pos < string_lim) {
994-
smart_str_appendl(&out_buf, pos, 1);
993+
smart_str_appendl(&out_buf, pos, 1);
995994
}
996995
pos++;
997996
}
@@ -1013,7 +1012,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
10131012
smart_str_free(&eval_buf);
10141013

10151014
if (err <= -2) {
1016-
smart_str_free(&out_buf);
1015+
smart_str_free(&out_buf);
10171016
RETVAL_FALSE;
10181017
} else {
10191018
smart_str_appendc(&out_buf, '\0');
@@ -1063,7 +1062,7 @@ PHP_FUNCTION(mb_split)
10631062

10641063
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &arg_pattern, &arg_pattern_len, &string, &string_len, &count) == FAILURE) {
10651064
RETURN_FALSE;
1066-
}
1065+
}
10671066

10681067
if (count > 0) {
10691068
count--;
@@ -1317,7 +1316,7 @@ PHP_FUNCTION(mb_ereg_search_init)
13171316
if (zend_parse_parameters(argc TSRMLS_CC, "z|ss", &arg_str, &arg_pattern, &arg_pattern_len, &arg_options, &arg_options_len) == FAILURE) {
13181317
return;
13191318
}
1320-
1319+
13211320
if (argc > 1 && arg_pattern_len == 0) {
13221321
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty pattern");
13231322
RETURN_FALSE;
@@ -1416,7 +1415,7 @@ PHP_FUNCTION(mb_ereg_search_setpos)
14161415
/* }}} */
14171416

14181417
/* {{{ php_mb_regex_set_options */
1419-
static void _php_mb_regex_set_options(OnigOptionType options, OnigSyntaxType *syntax, OnigOptionType *prev_options, OnigSyntaxType **prev_syntax TSRMLS_DC)
1418+
static void _php_mb_regex_set_options(OnigOptionType options, OnigSyntaxType *syntax, OnigOptionType *prev_options, OnigSyntaxType **prev_syntax TSRMLS_DC)
14201419
{
14211420
if (prev_options != NULL) {
14221421
*prev_options = MBREX(regex_default_options);

ext/mbstring/tests/bug72402.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Bug #72402: _php_mb_regex_ereg_replace_exec - double free
3+
--SKIPIF--
4+
<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
5+
--FILE--
6+
<?php
7+
function throwit() {
8+
throw new Exception('it');
9+
}
10+
$var10 = "throwit";
11+
try {
12+
$var14 = mb_ereg_replace_callback("", $var10, "");
13+
} catch(Exception $e) {}
14+
?>
15+
DONE
16+
--EXPECT--
17+
DONE

0 commit comments

Comments
 (0)