33
33
#include <stddef.h>
34
34
#include <assert.h>
35
35
#include <stdbool.h>
36
+ #include <limits.h>
36
37
#include "private.h" /* For _bc_rm_leading_zeros() */
37
38
#include "zend_alloc.h"
38
39
39
40
40
41
#if SIZEOF_SIZE_T >= 8
41
42
# define BC_MUL_UINT_DIGITS 8
42
- # define BC_MUL_UINT_OVERFLOW 100000000
43
+ # define BC_MUL_UINT_OVERFLOW (BC_UINT_T) 100000000
44
+ # define BC_MUL_MAX_ADD_COUNT (ULONG_MAX / (BC_MUL_UINT_OVERFLOW * BC_MUL_UINT_OVERFLOW))
43
45
#else
44
46
# define BC_MUL_UINT_DIGITS 4
45
- # define BC_MUL_UINT_OVERFLOW 10000
47
+ # define BC_MUL_UINT_OVERFLOW (BC_UINT_T) 10000
48
+ # define BC_MUL_MAX_ADD_COUNT (UINT_MAX / (BC_MUL_UINT_OVERFLOW * BC_MUL_UINT_OVERFLOW))
46
49
#endif
47
50
48
51
49
52
/* Multiply utility routines */
50
53
54
+ static inline void bc_digits_adjustment (BC_UINT_T * prod_uint , size_t prod_arr_size )
55
+ {
56
+ for (size_t i = 0 ; i < prod_arr_size - 1 ; i ++ ) {
57
+ prod_uint [i + 1 ] += prod_uint [i ] / BC_MUL_UINT_OVERFLOW ;
58
+ prod_uint [i ] %= BC_MUL_UINT_OVERFLOW ;
59
+ }
60
+ }
61
+
51
62
/*
52
63
* Converts BCD to uint, going backwards from pointer n by the number of
53
64
* characters specified by len.
@@ -141,7 +152,18 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc
141
152
bc_convert_to_uint (n2_uint , n2end , n2len );
142
153
143
154
/* Multiplication and addition */
155
+ size_t count = 0 ;
144
156
for (i = 0 ; i < n1_arr_size ; i ++ ) {
157
+ /*
158
+ * This calculation adds the result multiple times to the array entries.
159
+ * When multiplying large numbers of digits, there is a possibility of
160
+ * overflow, so digit adjustment is performed beforehand.
161
+ */
162
+ if (UNEXPECTED (count >= BC_MUL_MAX_ADD_COUNT )) {
163
+ bc_digits_adjustment (prod_uint , prod_arr_size );
164
+ count = 0 ;
165
+ }
166
+ count ++ ;
145
167
for (size_t j = 0 ; j < n2_arr_size ; j ++ ) {
146
168
prod_uint [i + j ] += n1_uint [i ] * n2_uint [j ];
147
169
}
@@ -151,10 +173,7 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc
151
173
* Move a value exceeding 4/8 digits by carrying to the next digit.
152
174
* However, the last digit does nothing.
153
175
*/
154
- for (i = 0 ; i < prod_arr_size - 1 ; i ++ ) {
155
- prod_uint [i + 1 ] += prod_uint [i ] / BC_MUL_UINT_OVERFLOW ;
156
- prod_uint [i ] %= BC_MUL_UINT_OVERFLOW ;
157
- }
176
+ bc_digits_adjustment (prod_uint , prod_arr_size );
158
177
159
178
/* Convert to bc_num */
160
179
* prod = bc_new_num_nonzeroed (prodlen , 0 );
0 commit comments