Skip to content

ext/bcmath: If size of BC_VECTOR array is within 64 bytes, stack area is now used #18065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ PHP NEWS
- BCMath:
. Simplify `bc_divide()` code. (SakiTakamachi)
. If the result is 0, n_scale is set to 0. (SakiTakamachi)
. If size of BC_VECTOR array is within 64 bytes, stack area is now used.
(SakiTakamachi)

- CLI:
. Add --ini=diff to print INI settings changed from the builtin default.
Expand Down
14 changes: 12 additions & 2 deletions ext/bcmath/libbcmath/src/div.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,15 @@ static void bc_do_div(
size_t quot_arr_size = numerator_arr_size - divisor_arr_size + 1;
size_t quot_real_arr_size = MIN(quot_arr_size, (quot_size + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE);

BC_VECTOR *numerator_vectors = safe_emalloc(numerator_arr_size + divisor_arr_size + quot_arr_size, sizeof(BC_VECTOR), 0);
BC_VECTOR stack_vectors[BC_STACK_VECTOR_SIZE];
size_t allocation_arr_size = numerator_arr_size + divisor_arr_size + quot_arr_size;

BC_VECTOR *numerator_vectors;
if (allocation_arr_size <= BC_STACK_VECTOR_SIZE) {
numerator_vectors = stack_vectors;
} else {
numerator_vectors = safe_emalloc(allocation_arr_size, sizeof(BC_VECTOR), 0);
}
BC_VECTOR *divisor_vectors = numerator_vectors + numerator_arr_size;
BC_VECTOR *quot_vectors = divisor_vectors + divisor_arr_size;

Expand Down Expand Up @@ -302,7 +310,9 @@ static void bc_do_div(
quot_vectors[i] /= BASE;
}

efree(numerator_vectors);
if (allocation_arr_size > BC_STACK_VECTOR_SIZE) {
efree(numerator_vectors);
}
}

static inline void bc_divide_by_one(bc_num numerator, bc_num *quot, size_t quot_scale)
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/libbcmath/src/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
# define BC_LITTLE_ENDIAN 1
#endif

/* 64-bytes for 64-bit */
#define BC_STACK_VECTOR_SIZE 8

/*
* Adding more than this many times may cause uint32_t/uint64_t to overflow.
* Typically this is 1844 for 64bit and 42 for 32bit.
Expand Down
26 changes: 17 additions & 9 deletions ext/bcmath/libbcmath/src/recmul.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,21 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc
size_t n2_arr_size = (n2len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE;
size_t prod_arr_size = (prodlen + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE;

/*
* let's say that N is the max of n1len and n2len (and a multiple of BC_VECTOR_SIZE for simplicity),
* then this sum is <= N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE - 1
* which is equal to N - 1 if BC_VECTOR_SIZE is 4, and N/2 - 1 if BC_VECTOR_SIZE is 8.
*/
BC_VECTOR *buf = safe_emalloc(n1_arr_size + n2_arr_size + prod_arr_size, sizeof(BC_VECTOR), 0);
BC_VECTOR stack_vectors[BC_STACK_VECTOR_SIZE];
size_t allocation_arr_size = n1_arr_size + n2_arr_size + prod_arr_size;

BC_VECTOR *n1_vector = buf;
BC_VECTOR *n2_vector = buf + n1_arr_size;
BC_VECTOR *n1_vector;
if (allocation_arr_size <= BC_STACK_VECTOR_SIZE) {
n1_vector = stack_vectors;
} else {
/*
* let's say that N is the max of n1len and n2len (and a multiple of BC_VECTOR_SIZE for simplicity),
* then this sum is <= N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE - 1
* which is equal to N - 1 if BC_VECTOR_SIZE is 4, and N/2 - 1 if BC_VECTOR_SIZE is 8.
*/
n1_vector = safe_emalloc(allocation_arr_size, sizeof(BC_VECTOR), 0);
}
BC_VECTOR *n2_vector = n1_vector + n1_arr_size;
BC_VECTOR *prod_vector = n2_vector + n2_arr_size;

for (i = 0; i < prod_arr_size; i++) {
Expand Down Expand Up @@ -188,7 +194,9 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc

bc_mul_finish_from_vector(prod_vector, prod_arr_size, prodlen, prod);

efree(buf);
if (allocation_arr_size > BC_STACK_VECTOR_SIZE) {
efree(n1_vector);
}
}

/** This is bc_standard_mul implementation for square */
Expand Down