@@ -106,6 +106,73 @@ PHP_GMP_API zend_class_entry *php_gmp_class_entry(void) {
106
106
#define GET_GMP_FROM_ZVAL (zval ) \
107
107
GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num
108
108
109
+ #ifndef GMP_SI_MAX
110
+ # define GMP_SI_MAX (GMP_NUMB_MAX >> 1)
111
+ #endif
112
+ #ifndef GMP_SI_MIN
113
+ # define GMP_SI_MIN (-(1LL << (GMP_NUMB_BITS - 1)))
114
+ #endif
115
+ #if GMP_NUMB_BITS < SIZEOF_ZEND_LONG * 8
116
+ void gmp_set_zlong (mpz_t z , zend_long zlong ) {
117
+ if (zlong <= GMP_SI_MAX && zlong >= GMP_SI_MIN ) {
118
+ mpz_set_si (z , zlong );
119
+ } else if (zlong >= 0 ) {
120
+ mpz_import (z , 1 , 1 , sizeof (zend_long ), 0 , 0 , & zlong );
121
+ } else {
122
+ mpz_import (z , 1 , 1 , sizeof (zend_long ), 0 , 0 , & zlong );
123
+ mpz_neg (z , z );
124
+ }
125
+ }
126
+
127
+ int gmp_fits_zlong_p (mpz_t z ) {
128
+ int result = 1 ;
129
+ mpz_t z_min_max ;
130
+ zend_long min_max ;
131
+
132
+ if (mpz_cmp_si (z , GMP_SI_MAX ) > 0 ) {
133
+ min_max = ZEND_LONG_MAX ;
134
+ mpz_init (z_min_max );
135
+ mpz_import (z_min_max , 1 , 1 , sizeof (zend_long ), 0 , 0 , & min_max );
136
+ result = mpz_cmp (z , z_min_max ) <= 0 ;
137
+ mpz_clear (z_min_max );
138
+ } else if (mpz_cmp_si (z , GMP_SI_MIN ) < 0 ) {
139
+ min_max = ZEND_LONG_MIN ;
140
+ mpz_init (z_min_max );
141
+ mpz_import (z_min_max , 1 , 1 , sizeof (zend_long ), 0 , 0 , & min_max );
142
+ mpz_neg (z_min_max , z_min_max );
143
+ result = mpz_cmp (z , z_min_max ) >= 0 ;
144
+ mpz_clear (z_min_max );
145
+ }
146
+
147
+ return result ;
148
+ }
149
+
150
+ zend_long gmp_get_zlong (mpz_t z ) {
151
+ zend_long result ;
152
+ zend_long mask = -1 ;
153
+ mpz_t z_tmp ;
154
+ mpz_t z_mask ;
155
+
156
+ if (mpz_cmp_si (z , GMP_SI_MAX ) > 0 || mpz_cmp_si (z , GMP_SI_MIN ) < 0 ) {
157
+ mpz_init (z_tmp );
158
+ mpz_init (z_mask );
159
+ mpz_import (z_mask , 1 , 1 , sizeof (zend_long ), 0 , 0 , & mask );
160
+ mpz_and (z_tmp , z , z_mask );
161
+ mpz_export (& result , NULL , 0 , sizeof (zend_long ), 0 , 0 , z_tmp );
162
+ mpz_clear (z_mask );
163
+ mpz_clear (z_tmp );
164
+ } else {
165
+ result = mpz_get_si (z );
166
+ }
167
+
168
+ return result ;
169
+ }
170
+ #else
171
+ # define gmp_set_zlong (z , l ) mpz_set_si(z, l)
172
+ # define gmp_fits_zlong_p (z ) mpz_fits_si_p(z)
173
+ # define gmp_get_zlong (z ) mpz_get_si(z)
174
+ #endif
175
+
109
176
static void gmp_strval (zval * result , mpz_t gmpnum , int base );
110
177
static zend_result convert_zstr_to_gmp (mpz_t gmp_number , const zend_string * val , zend_long base , uint32_t arg_pos );
111
178
@@ -129,7 +196,7 @@ static bool gmp_zend_parse_arg_into_mpz_ex(
129
196
}
130
197
131
198
if (Z_TYPE_P (arg ) == IS_LONG ) {
132
- mpz_set_si (* destination_mpz_ptr , Z_LVAL_P (arg ));
199
+ gmp_set_zlong (* destination_mpz_ptr , Z_LVAL_P (arg ));
133
200
return true;
134
201
}
135
202
@@ -145,7 +212,7 @@ static bool gmp_zend_parse_arg_into_mpz_ex(
145
212
return false;
146
213
}
147
214
148
- mpz_set_si (* destination_mpz_ptr , lval );
215
+ gmp_set_zlong (* destination_mpz_ptr , lval );
149
216
150
217
return true;
151
218
}
@@ -243,16 +310,16 @@ static zend_result gmp_cast_object(zend_object *readobj, zval *writeobj, int typ
243
310
return SUCCESS ;
244
311
case IS_LONG :
245
312
gmpnum = GET_GMP_OBJECT_FROM_OBJ (readobj )-> num ;
246
- ZVAL_LONG (writeobj , mpz_get_si (gmpnum ));
313
+ ZVAL_LONG (writeobj , gmp_get_zlong (gmpnum ));
247
314
return SUCCESS ;
248
315
case IS_DOUBLE :
249
316
gmpnum = GET_GMP_OBJECT_FROM_OBJ (readobj )-> num ;
250
317
ZVAL_DOUBLE (writeobj , mpz_get_d (gmpnum ));
251
318
return SUCCESS ;
252
319
case _IS_NUMBER :
253
320
gmpnum = GET_GMP_OBJECT_FROM_OBJ (readobj )-> num ;
254
- if (mpz_fits_si_p (gmpnum )) {
255
- ZVAL_LONG (writeobj , mpz_get_si (gmpnum ));
321
+ if (gmp_fits_zlong_p (gmpnum )) {
322
+ ZVAL_LONG (writeobj , gmp_get_zlong (gmpnum ));
256
323
} else {
257
324
ZVAL_DOUBLE (writeobj , mpz_get_d (gmpnum ));
258
325
}
@@ -712,7 +779,7 @@ static zend_result gmp_initialize_number(mpz_ptr gmp_number, const zend_string *
712
779
return convert_zstr_to_gmp (gmp_number , arg_str , base , 1 );
713
780
}
714
781
715
- mpz_set_si (gmp_number , arg_l );
782
+ gmp_set_zlong (gmp_number , arg_l );
716
783
return SUCCESS ;
717
784
}
718
785
@@ -862,7 +929,7 @@ ZEND_FUNCTION(gmp_intval)
862
929
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum )
863
930
ZEND_PARSE_PARAMETERS_END ();
864
931
865
- RETVAL_LONG (mpz_get_si (gmpnum ));
932
+ RETVAL_LONG (gmp_get_zlong (gmpnum ));
866
933
}
867
934
/* }}} */
868
935
@@ -1526,8 +1593,13 @@ ZEND_FUNCTION(gmp_random_range)
1526
1593
}
1527
1594
/* }}} */
1528
1595
1596
+ #if SIZEOF_SIZE_T >= SIZEOF_ZEND_LONG
1597
+ # define GMP_SAFE_BITINDEX_MAX ((mp_bitcnt_t)INT_MAX * GMP_NUMB_BITS)
1598
+ #else
1599
+ # define GMP_SAFE_BITINDEX_MAX ((mp_bitcnt_t)INT_MAX * GMP_NUMB_BITS - 1)
1600
+ #endif
1529
1601
static bool gmp_is_bit_index_valid (zend_long index ) {
1530
- return index >= 0 && (index / GMP_NUMB_BITS < INT_MAX ) ;
1602
+ return index >= 0 && (zend_ulong ) index <= GMP_SAFE_BITINDEX_MAX ;
1531
1603
}
1532
1604
1533
1605
/* {{{ Sets or clear bit in a */
@@ -1543,7 +1615,7 @@ ZEND_FUNCTION(gmp_setbit)
1543
1615
}
1544
1616
1545
1617
if (!gmp_is_bit_index_valid (index )) {
1546
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1618
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1547
1619
RETURN_THROWS ();
1548
1620
}
1549
1621
@@ -1569,7 +1641,7 @@ ZEND_FUNCTION(gmp_clrbit)
1569
1641
}
1570
1642
1571
1643
if (!gmp_is_bit_index_valid (index )) {
1572
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1644
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1573
1645
RETURN_THROWS ();
1574
1646
}
1575
1647
@@ -1590,7 +1662,7 @@ ZEND_FUNCTION(gmp_testbit)
1590
1662
ZEND_PARSE_PARAMETERS_END ();
1591
1663
1592
1664
if (!gmp_is_bit_index_valid (index )) {
1593
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1665
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1594
1666
RETURN_THROWS ();
1595
1667
}
1596
1668
@@ -1602,26 +1674,44 @@ ZEND_FUNCTION(gmp_testbit)
1602
1674
ZEND_FUNCTION (gmp_popcount )
1603
1675
{
1604
1676
mpz_ptr gmpnum_a ;
1677
+ mp_bitcnt_t result ;
1605
1678
1606
1679
ZEND_PARSE_PARAMETERS_START (1 , 1 )
1607
1680
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1608
1681
ZEND_PARSE_PARAMETERS_END ();
1609
1682
1610
- RETURN_LONG (mpz_popcount (gmpnum_a ));
1683
+ result = mpz_popcount (gmpnum_a );
1684
+
1685
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1686
+ if (SIZE_MAX == result ) {
1687
+ RETURN_LONG (-1 );
1688
+ }
1689
+ #endif
1690
+
1691
+ RETURN_LONG (result );
1611
1692
}
1612
1693
/* }}} */
1613
1694
1614
1695
/* {{{ Calculates hamming distance between a and b */
1615
1696
ZEND_FUNCTION (gmp_hamdist )
1616
1697
{
1617
1698
mpz_ptr gmpnum_a , gmpnum_b ;
1699
+ mp_bitcnt_t result ;
1618
1700
1619
1701
ZEND_PARSE_PARAMETERS_START (2 , 2 )
1620
1702
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1621
1703
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_b )
1622
1704
ZEND_PARSE_PARAMETERS_END ();
1623
1705
1624
- RETURN_LONG (mpz_hamdist (gmpnum_a , gmpnum_b ));
1706
+ result = mpz_hamdist (gmpnum_a , gmpnum_b );
1707
+
1708
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1709
+ if (SIZE_MAX == result ) {
1710
+ RETURN_LONG (-1 );
1711
+ }
1712
+ #endif
1713
+
1714
+ RETURN_LONG (result );
1625
1715
}
1626
1716
/* }}} */
1627
1717
@@ -1630,18 +1720,27 @@ ZEND_FUNCTION(gmp_scan0)
1630
1720
{
1631
1721
mpz_ptr gmpnum_a ;
1632
1722
zend_long start ;
1723
+ mp_bitcnt_t result ;
1633
1724
1634
1725
ZEND_PARSE_PARAMETERS_START (2 , 2 )
1635
1726
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1636
1727
Z_PARAM_LONG (start )
1637
1728
ZEND_PARSE_PARAMETERS_END ();
1638
1729
1639
1730
if (!gmp_is_bit_index_valid (start )) {
1640
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1731
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1641
1732
RETURN_THROWS ();
1642
1733
}
1643
1734
1644
- RETURN_LONG (mpz_scan0 (gmpnum_a , start ));
1735
+ result = mpz_scan0 (gmpnum_a , start );
1736
+
1737
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1738
+ if (SIZE_MAX == result ) {
1739
+ RETURN_LONG (-1 );
1740
+ }
1741
+ #endif
1742
+
1743
+ RETURN_LONG (result );
1645
1744
}
1646
1745
/* }}} */
1647
1746
@@ -1650,18 +1749,28 @@ ZEND_FUNCTION(gmp_scan1)
1650
1749
{
1651
1750
mpz_ptr gmpnum_a ;
1652
1751
zend_long start ;
1752
+ mp_bitcnt_t result ;
1753
+
1653
1754
1654
1755
ZEND_PARSE_PARAMETERS_START (2 , 2 )
1655
1756
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1656
1757
Z_PARAM_LONG (start )
1657
1758
ZEND_PARSE_PARAMETERS_END ();
1658
1759
1659
1760
if (!gmp_is_bit_index_valid (start )) {
1660
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1761
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1661
1762
RETURN_THROWS ();
1662
1763
}
1663
1764
1664
- RETURN_LONG (mpz_scan1 (gmpnum_a , start ));
1765
+ result = mpz_scan1 (gmpnum_a , start );
1766
+
1767
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1768
+ if (SIZE_MAX == result ) {
1769
+ RETURN_LONG (-1 );
1770
+ }
1771
+ #endif
1772
+
1773
+ RETURN_LONG (result );
1665
1774
}
1666
1775
/* }}} */
1667
1776
0 commit comments