Skip to content

Commit 70b5a4d

Browse files
authored
BCMath: Avoid using the heap for temporary objects by using arena allocations (#14170)
* BCMath: Avoid using the heap for temporary objects by using arena allocations * Fix alignment * Improve size computation
1 parent 0642855 commit 70b5a4d

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

ext/bcmath/bcmath.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@
2929
#include "php_bcmath.h"
3030
#include "libbcmath/src/bcmath.h"
3131

32+
/* Always pair SETUP with TEARDOWN, and do so in the outer scope!
33+
* Should not be used when data can escape the function. */
34+
#define BC_ARENA_SETUP \
35+
char bc_arena[BC_ARENA_SIZE]; \
36+
BCG(arena) = bc_arena;
37+
38+
#define BC_ARENA_TEARDOWN \
39+
BCG(arena) = NULL; \
40+
BCG(arena_offset) = 0;
41+
3242
ZEND_DECLARE_MODULE_GLOBALS(bcmath)
3343
static PHP_GINIT_FUNCTION(bcmath);
3444
static PHP_GSHUTDOWN_FUNCTION(bcmath);
@@ -89,6 +99,8 @@ static PHP_GINIT_FUNCTION(bcmath)
8999
ZEND_TSRMLS_CACHE_UPDATE();
90100
#endif
91101
bcmath_globals->bc_precision = 0;
102+
bcmath_globals->arena = NULL;
103+
bcmath_globals->arena_offset = 0;
92104
bc_init_numbers();
93105
}
94106
/* }}} */
@@ -99,6 +111,8 @@ static PHP_GSHUTDOWN_FUNCTION(bcmath)
99111
_bc_free_num_ex(&bcmath_globals->_zero_, 1);
100112
_bc_free_num_ex(&bcmath_globals->_one_, 1);
101113
_bc_free_num_ex(&bcmath_globals->_two_, 1);
114+
bcmath_globals->arena = NULL;
115+
bcmath_globals->arena_offset = 0;
102116
}
103117
/* }}} */
104118

@@ -167,6 +181,8 @@ PHP_FUNCTION(bcadd)
167181
scale = (int) scale_param;
168182
}
169183

184+
BC_ARENA_SETUP;
185+
170186
if (php_str2num(&first, left) == FAILURE) {
171187
zend_argument_value_error(1, "is not well-formed");
172188
goto cleanup;
@@ -185,6 +201,7 @@ PHP_FUNCTION(bcadd)
185201
bc_free_num(&first);
186202
bc_free_num(&second);
187203
bc_free_num(&result);
204+
BC_ARENA_TEARDOWN;
188205
};
189206
}
190207
/* }}} */
@@ -214,6 +231,8 @@ PHP_FUNCTION(bcsub)
214231
scale = (int) scale_param;
215232
}
216233

234+
BC_ARENA_SETUP;
235+
217236
if (php_str2num(&first, left) == FAILURE) {
218237
zend_argument_value_error(1, "is not well-formed");
219238
goto cleanup;
@@ -232,6 +251,7 @@ PHP_FUNCTION(bcsub)
232251
bc_free_num(&first);
233252
bc_free_num(&second);
234253
bc_free_num(&result);
254+
BC_ARENA_TEARDOWN;
235255
};
236256
}
237257
/* }}} */
@@ -261,6 +281,8 @@ PHP_FUNCTION(bcmul)
261281
scale = (int) scale_param;
262282
}
263283

284+
BC_ARENA_SETUP;
285+
264286
if (php_str2num(&first, left) == FAILURE) {
265287
zend_argument_value_error(1, "is not well-formed");
266288
goto cleanup;
@@ -279,6 +301,7 @@ PHP_FUNCTION(bcmul)
279301
bc_free_num(&first);
280302
bc_free_num(&second);
281303
bc_free_num(&result);
304+
BC_ARENA_TEARDOWN;
282305
};
283306
}
284307
/* }}} */
@@ -308,6 +331,8 @@ PHP_FUNCTION(bcdiv)
308331
scale = (int) scale_param;
309332
}
310333

334+
BC_ARENA_SETUP;
335+
311336
bc_init_num(&result);
312337

313338
if (php_str2num(&first, left) == FAILURE) {
@@ -331,6 +356,7 @@ PHP_FUNCTION(bcdiv)
331356
bc_free_num(&first);
332357
bc_free_num(&second);
333358
bc_free_num(&result);
359+
BC_ARENA_TEARDOWN;
334360
};
335361
}
336362
/* }}} */
@@ -360,6 +386,8 @@ PHP_FUNCTION(bcmod)
360386
scale = (int) scale_param;
361387
}
362388

389+
BC_ARENA_SETUP;
390+
363391
bc_init_num(&result);
364392

365393
if (php_str2num(&first, left) == FAILURE) {
@@ -383,6 +411,7 @@ PHP_FUNCTION(bcmod)
383411
bc_free_num(&first);
384412
bc_free_num(&second);
385413
bc_free_num(&result);
414+
BC_ARENA_TEARDOWN;
386415
};
387416
}
388417
/* }}} */
@@ -413,6 +442,8 @@ PHP_FUNCTION(bcpowmod)
413442
scale = (int) scale_param;
414443
}
415444

445+
BC_ARENA_SETUP;
446+
416447
bc_init_num(&result);
417448

418449
if (php_str2num(&bc_base, base_str) == FAILURE) {
@@ -458,6 +489,7 @@ PHP_FUNCTION(bcpowmod)
458489
bc_free_num(&bc_expo);
459490
bc_free_num(&bc_modulus);
460491
bc_free_num(&result);
492+
BC_ARENA_TEARDOWN;
461493
};
462494
}
463495
/* }}} */
@@ -487,6 +519,8 @@ PHP_FUNCTION(bcpow)
487519
scale = (int) scale_param;
488520
}
489521

522+
BC_ARENA_SETUP;
523+
490524
bc_init_num(&result);
491525

492526
if (php_str2num(&first, base_str) == FAILURE) {
@@ -518,6 +552,7 @@ PHP_FUNCTION(bcpow)
518552
bc_free_num(&first);
519553
bc_free_num(&bc_exponent);
520554
bc_free_num(&result);
555+
BC_ARENA_TEARDOWN;
521556
};
522557
}
523558
/* }}} */
@@ -546,6 +581,8 @@ PHP_FUNCTION(bcsqrt)
546581
scale = (int) scale_param;
547582
}
548583

584+
BC_ARENA_SETUP;
585+
549586
if (php_str2num(&result, left) == FAILURE) {
550587
zend_argument_value_error(1, "is not well-formed");
551588
goto cleanup;
@@ -559,6 +596,7 @@ PHP_FUNCTION(bcsqrt)
559596

560597
cleanup: {
561598
bc_free_num(&result);
599+
BC_ARENA_TEARDOWN;
562600
};
563601
}
564602
/* }}} */
@@ -588,6 +626,8 @@ PHP_FUNCTION(bccomp)
588626
scale = (int) scale_param;
589627
}
590628

629+
BC_ARENA_SETUP;
630+
591631
if (!bc_str2num(&first, ZSTR_VAL(left), ZSTR_VAL(left) + ZSTR_LEN(left), scale, false)) {
592632
zend_argument_value_error(1, "is not well-formed");
593633
goto cleanup;
@@ -603,6 +643,7 @@ PHP_FUNCTION(bccomp)
603643
cleanup: {
604644
bc_free_num(&first);
605645
bc_free_num(&second);
646+
BC_ARENA_TEARDOWN;
606647
};
607648
}
608649
/* }}} */
@@ -617,6 +658,8 @@ static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor)
617658
Z_PARAM_STR(numstr)
618659
ZEND_PARSE_PARAMETERS_END();
619660

661+
BC_ARENA_SETUP;
662+
620663
if (php_str2num(&num, numstr) == FAILURE) {
621664
zend_argument_value_error(1, "is not well-formed");
622665
goto cleanup;
@@ -628,6 +671,7 @@ static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor)
628671
cleanup: {
629672
bc_free_num(&num);
630673
bc_free_num(&result);
674+
BC_ARENA_TEARDOWN;
631675
};
632676
}
633677
/* }}} */
@@ -676,6 +720,8 @@ PHP_FUNCTION(bcround)
676720
return;
677721
}
678722

723+
BC_ARENA_SETUP;
724+
679725
bc_init_num(&result);
680726

681727
if (php_str2num(&num, numstr) == FAILURE) {
@@ -689,6 +735,7 @@ PHP_FUNCTION(bcround)
689735
cleanup: {
690736
bc_free_num(&num);
691737
bc_free_num(&result);
738+
BC_ARENA_TEARDOWN;
692739
};
693740
}
694741
/* }}} */

ext/bcmath/libbcmath/src/init.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,25 @@
3535
#include <string.h>
3636
#include "zend_alloc.h"
3737

38-
static zend_always_inline bc_num _bc_new_num_nonzeroed_ex_internal(size_t length, size_t scale, bool persistent)
38+
static bc_num _bc_new_num_nonzeroed_ex_internal(size_t length, size_t scale, bool persistent)
3939
{
40-
/* PHP Change: malloc() -> pemalloc(), removed free_list code, merged n_ptr and n_value */
41-
bc_num temp = safe_pemalloc(1, sizeof(bc_struct) + length, scale, persistent);
40+
size_t required_size = zend_safe_address_guarded(1, sizeof(bc_struct) + (ZEND_MM_ALIGNMENT - 1) + length, scale);
41+
required_size &= -ZEND_MM_ALIGNMENT;
42+
bc_num temp;
43+
44+
if (!persistent && BCG(arena) && required_size <= BC_ARENA_SIZE - BCG(arena_offset)) {
45+
temp = (bc_num) (BCG(arena) + BCG(arena_offset));
46+
BCG(arena_offset) += required_size;
47+
temp->n_refs = 2; /* prevent freeing */
48+
} else {
49+
/* PHP Change: malloc() -> pemalloc(), removed free_list code, merged n_ptr and n_value */
50+
temp = pemalloc(required_size, persistent);
51+
temp->n_refs = 1;
52+
}
53+
4254
temp->n_sign = PLUS;
4355
temp->n_len = length;
4456
temp->n_scale = scale;
45-
temp->n_refs = 1;
4657
temp->n_value = (char *) temp + sizeof(bc_struct);
4758
return temp;
4859
}

ext/bcmath/php_bcmath.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ extern zend_module_entry bcmath_module_entry;
2727
#include "php_version.h"
2828
#define PHP_BCMATH_VERSION PHP_VERSION
2929

30+
#define BC_ARENA_SIZE 256
31+
3032
ZEND_BEGIN_MODULE_GLOBALS(bcmath)
3133
bc_num _zero_;
3234
bc_num _one_;
3335
bc_num _two_;
3436
int bc_precision;
37+
char *arena;
38+
size_t arena_offset;
3539
ZEND_END_MODULE_GLOBALS(bcmath)
3640

3741
#if defined(ZTS) && defined(COMPILE_DL_BCMATH)

0 commit comments

Comments
 (0)