58
58
#include "zend_multiply.h"
59
59
#include "zend_bitset.h"
60
60
#include "zend_mmap.h"
61
+ #include "zend_portability.h"
62
+ #include "ext/random/php_random_csprng.h"
63
+ #include "ext/random/php_random.h"
61
64
#include <signal.h>
62
65
63
66
#ifdef HAVE_UNISTD_H
@@ -245,6 +248,7 @@ struct _zend_mm_heap {
245
248
size_t size ; /* current memory usage */
246
249
size_t peak ; /* peak memory usage */
247
250
#endif
251
+ uintptr_t key ; /* free slot shadow ptr key */
248
252
zend_mm_free_slot * free_slot [ZEND_MM_BINS ]; /* free lists for small sizes */
249
253
#if ZEND_MM_STAT || ZEND_MM_LIMIT
250
254
size_t real_size ; /* current size of allocated pages */
@@ -275,6 +279,8 @@ struct _zend_mm_heap {
275
279
} custom_heap ;
276
280
HashTable * tracked_allocs ;
277
281
#endif
282
+ pid_t pid ;
283
+ php_random_status_state_xoshiro256starstar random_state ;
278
284
};
279
285
280
286
struct _zend_mm_chunk {
@@ -318,19 +324,37 @@ struct _zend_mm_huge_list {
318
324
#define ZEND_MM_PAGE_ADDR (chunk , page_num ) \
319
325
((void*)(((zend_mm_page*)(chunk)) + (page_num)))
320
326
321
- #define _BIN_DATA_SIZE (num , size , elements , pages , x , y ) size,
327
+ #define _BIN_DATA_SIZE (num , size , elements , pages , x , y ) \
328
+ /* Need two words for free slot pointer and shadow */ \
329
+ MAX(size, sizeof(zend_mm_free_slot*)*2)
330
+ #define _BIN_DATA_SIZE_C (num , size , elements , pages , x , y ) \
331
+ _BIN_DATA_SIZE(num, size, elements, pages, x, y),
322
332
static const uint32_t bin_data_size [] = {
323
- ZEND_MM_BINS_INFO (_BIN_DATA_SIZE , x , y )
333
+ ZEND_MM_BINS_INFO (_BIN_DATA_SIZE_C , x , y )
324
334
};
325
335
326
- #define _BIN_DATA_ELEMENTS (num , size , elements , pages , x , y ) elements,
336
+ #define _BIN_DATA_ELEMENTS (num , size , elements , pages , x , y ) \
337
+ /* Adjusting size requires adjusting elements */ \
338
+ (elements / (_BIN_DATA_SIZE(num, size, elements, pages, x, y) / size))
339
+ #define _BIN_DATA_ELEMENTS_C (num , size , elements , pages , x , y ) \
340
+ _BIN_DATA_ELEMENTS(num, size, elements, pages, x, y),
327
341
static const uint32_t bin_elements [] = {
328
- ZEND_MM_BINS_INFO (_BIN_DATA_ELEMENTS , x , y )
342
+ ZEND_MM_BINS_INFO (_BIN_DATA_ELEMENTS_C , x , y )
329
343
};
330
344
331
- #define _BIN_DATA_PAGES (num , size , elements , pages , x , y ) pages,
345
+ #define _BIN_DATA_PAGES (num , size , elements , pages , x , y ) pages
346
+ #define _BIN_DATA_PAGES_C (num , size , elements , pages , x , y ) \
347
+ _BIN_DATA_PAGES(num, size, elements, pages, x, y),
332
348
static const uint32_t bin_pages [] = {
333
- ZEND_MM_BINS_INFO (_BIN_DATA_PAGES , x , y )
349
+ ZEND_MM_BINS_INFO (_BIN_DATA_PAGES_C , x , y )
350
+ };
351
+
352
+ #define _BIN_SHADOW_OFFSET (num , size , elements , pages , x , y ) \
353
+ (_BIN_DATA_SIZE(num, size, elements, pages, x, y) - sizeof(zend_mm_free_slot*))
354
+ #define _BIN_SHADOW_OFFSET_C (num , size , elements , pages , x , y ) \
355
+ _BIN_SHADOW_OFFSET(num, size, elements, pages, x, y),
356
+ static const uint32_t bin_shadow_offset [] = {
357
+ ZEND_MM_BINS_INFO (_BIN_SHADOW_OFFSET_C , x , y )
334
358
};
335
359
336
360
#if ZEND_DEBUG
@@ -1248,6 +1272,45 @@ static zend_always_inline int zend_mm_small_size_to_bin(size_t size)
1248
1272
1249
1273
#define ZEND_MM_SMALL_SIZE_TO_BIN (size ) zend_mm_small_size_to_bin(size)
1250
1274
1275
+ static zend_always_inline zend_mm_free_slot * zend_mm_encode_free_slot (zend_mm_heap * heap , zend_mm_free_slot * slot )
1276
+ {
1277
+ return (zend_mm_free_slot * )((uintptr_t )slot ^ heap -> key );
1278
+ }
1279
+
1280
+ static zend_always_inline zend_mm_free_slot * zend_mm_decode_free_slot (zend_mm_heap * heap , zend_mm_free_slot * slot )
1281
+ {
1282
+ return (zend_mm_free_slot * )((uintptr_t )slot ^ heap -> key );
1283
+ }
1284
+
1285
+ static zend_always_inline void zend_mm_set_next_free_slot (zend_mm_heap * heap , uint32_t bin_num , zend_mm_free_slot * slot , zend_mm_free_slot * next )
1286
+ {
1287
+ slot -> next_free_slot = next ;
1288
+ * (zend_mm_free_slot * * )((char * )slot + bin_shadow_offset [bin_num ]) = zend_mm_encode_free_slot (heap , next );
1289
+ }
1290
+
1291
+ static zend_always_inline void zend_mm_copy_next_free_slot (zend_mm_free_slot * dest , uint32_t bin_num , zend_mm_free_slot * from )
1292
+ {
1293
+ dest -> next_free_slot = from -> next_free_slot ;
1294
+ * (zend_mm_free_slot * * )((char * )dest + bin_shadow_offset [bin_num ]) = * (zend_mm_free_slot * * )((char * )from + bin_shadow_offset [bin_num ]);
1295
+ }
1296
+
1297
+ static ZEND_COLD ZEND_NORETURN void zend_mm_free_slot_corrupted (void )
1298
+ {
1299
+ zend_mm_panic ("zend_mm_heap corrupted" );
1300
+ }
1301
+
1302
+ static zend_always_inline zend_mm_free_slot * zend_mm_check_next_free_slot (zend_mm_heap * heap , uint32_t bin_num , zend_mm_free_slot * slot )
1303
+ {
1304
+ zend_mm_free_slot * next = slot -> next_free_slot ;
1305
+ zend_mm_free_slot * shadow = * (zend_mm_free_slot * * )((char * )slot + bin_shadow_offset [bin_num ]);
1306
+ if (EXPECTED (next != NULL )) {
1307
+ if (UNEXPECTED (next != zend_mm_decode_free_slot (heap , shadow ))) {
1308
+ zend_mm_free_slot_corrupted ();
1309
+ }
1310
+ }
1311
+ return (zend_mm_free_slot * )next ;
1312
+ }
1313
+
1251
1314
static zend_never_inline void * zend_mm_alloc_small_slow (zend_mm_heap * heap , uint32_t bin_num ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
1252
1315
{
1253
1316
zend_mm_chunk * chunk ;
@@ -1281,7 +1344,7 @@ static zend_never_inline void *zend_mm_alloc_small_slow(zend_mm_heap *heap, uint
1281
1344
end = (zend_mm_free_slot * )((char * )bin + (bin_data_size [bin_num ] * (bin_elements [bin_num ] - 1 )));
1282
1345
heap -> free_slot [bin_num ] = p = (zend_mm_free_slot * )((char * )bin + bin_data_size [bin_num ]);
1283
1346
do {
1284
- p -> next_free_slot = (zend_mm_free_slot * )((char * )p + bin_data_size [bin_num ]);
1347
+ zend_mm_set_next_free_slot ( heap , bin_num , p , (zend_mm_free_slot * )((char * )p + bin_data_size [bin_num ]) );
1285
1348
#if ZEND_DEBUG
1286
1349
do {
1287
1350
zend_mm_debug_info * dbg = (zend_mm_debug_info * )((char * )p + bin_data_size [bin_num ] - ZEND_MM_ALIGNED_SIZE (sizeof (zend_mm_debug_info )));
@@ -1317,7 +1380,7 @@ static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, int bin_
1317
1380
1318
1381
if (EXPECTED (heap -> free_slot [bin_num ] != NULL )) {
1319
1382
zend_mm_free_slot * p = heap -> free_slot [bin_num ];
1320
- heap -> free_slot [bin_num ] = p -> next_free_slot ;
1383
+ heap -> free_slot [bin_num ] = zend_mm_check_next_free_slot ( heap , bin_num , p ) ;
1321
1384
return p ;
1322
1385
} else {
1323
1386
return zend_mm_alloc_small_slow (heap , bin_num ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC );
@@ -1340,7 +1403,7 @@ static zend_always_inline void zend_mm_free_small(zend_mm_heap *heap, void *ptr,
1340
1403
#endif
1341
1404
1342
1405
p = (zend_mm_free_slot * )ptr ;
1343
- p -> next_free_slot = heap -> free_slot [bin_num ];
1406
+ zend_mm_set_next_free_slot ( heap , bin_num , p , heap -> free_slot [bin_num ]) ;
1344
1407
heap -> free_slot [bin_num ] = p ;
1345
1408
}
1346
1409
@@ -1904,6 +1967,27 @@ static void zend_mm_free_huge(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZE
1904
1967
/* Initialization */
1905
1968
/******************/
1906
1969
1970
+ static zend_result zend_mm_refresh_key (zend_mm_heap * heap )
1971
+ {
1972
+ php_random_result result = php_random_algo_xoshiro256starstar .generate (& heap -> random_state );
1973
+ ZEND_ASSERT (result .size == sizeof (uint64_t ));
1974
+ heap -> key = (uintptr_t ) result .result ;
1975
+ return SUCCESS ;
1976
+ }
1977
+
1978
+ static zend_result zend_mm_init_key (zend_mm_heap * heap )
1979
+ {
1980
+ uint64_t seed [4 ];
1981
+ if (php_random_bytes (& seed , sizeof (seed ), false) != SUCCESS ) {
1982
+ return FAILURE ;
1983
+ }
1984
+
1985
+ php_random_xoshiro256starstar_seed256 (& heap -> random_state ,
1986
+ seed [0 ], seed [1 ], seed [2 ], seed [3 ]);
1987
+
1988
+ return zend_mm_refresh_key (heap );
1989
+ }
1990
+
1907
1991
static zend_mm_heap * zend_mm_init (void )
1908
1992
{
1909
1993
zend_mm_chunk * chunk = (zend_mm_chunk * )zend_mm_chunk_alloc_int (ZEND_MM_CHUNK_SIZE , ZEND_MM_CHUNK_SIZE );
@@ -1940,6 +2024,12 @@ static zend_mm_heap *zend_mm_init(void)
1940
2024
heap -> size = 0 ;
1941
2025
heap -> peak = 0 ;
1942
2026
#endif
2027
+ if (zend_mm_init_key (heap ) != SUCCESS ) {
2028
+ #if ZEND_MM_ERROR
2029
+ fprintf (stderr , "Can't initialize heap\n" );
2030
+ #endif
2031
+ return NULL ;
2032
+ }
1943
2033
#if ZEND_MM_LIMIT
1944
2034
heap -> limit = (size_t )Z_L (-1 ) >> 1 ;
1945
2035
heap -> overflow = 0 ;
@@ -1951,12 +2041,13 @@ static zend_mm_heap *zend_mm_init(void)
1951
2041
heap -> storage = NULL ;
1952
2042
#endif
1953
2043
heap -> huge_list = NULL ;
2044
+ heap -> pid = getpid ();
1954
2045
return heap ;
1955
2046
}
1956
2047
1957
2048
ZEND_API size_t zend_mm_gc (zend_mm_heap * heap )
1958
2049
{
1959
- zend_mm_free_slot * p , * * q ;
2050
+ zend_mm_free_slot * p , * q ;
1960
2051
zend_mm_chunk * chunk ;
1961
2052
size_t page_offset ;
1962
2053
int page_num ;
@@ -1994,15 +2085,15 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
1994
2085
has_free_pages = true;
1995
2086
}
1996
2087
chunk -> map [page_num ] = ZEND_MM_SRUN_EX (i , free_counter );
1997
- p = p -> next_free_slot ;
2088
+ p = zend_mm_check_next_free_slot ( heap , i , p ) ;
1998
2089
}
1999
2090
2000
2091
if (!has_free_pages ) {
2001
2092
continue ;
2002
2093
}
2003
2094
2004
- q = & heap -> free_slot [i ];
2005
- p = * q ;
2095
+ q = ( zend_mm_free_slot * ) & heap -> free_slot [i ];
2096
+ p = q -> next_free_slot ;
2006
2097
while (p != NULL ) {
2007
2098
chunk = (zend_mm_chunk * )ZEND_MM_ALIGNED_BASE (p , ZEND_MM_CHUNK_SIZE );
2008
2099
ZEND_MM_CHECK (chunk -> heap == heap , "zend_mm_heap corrupted" );
@@ -2020,11 +2111,19 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
2020
2111
ZEND_ASSERT (ZEND_MM_SRUN_BIN_NUM (info ) == i );
2021
2112
if (ZEND_MM_SRUN_FREE_COUNTER (info ) == bin_elements [i ]) {
2022
2113
/* remove from cache */
2023
- p = p -> next_free_slot ;
2024
- * q = p ;
2114
+ if (q == (zend_mm_free_slot * )& heap -> free_slot [i ]) {
2115
+ q -> next_free_slot = zend_mm_check_next_free_slot (heap , i , p );
2116
+ } else {
2117
+ zend_mm_copy_next_free_slot ((zend_mm_free_slot * )q , i , p );
2118
+ }
2119
+ p = zend_mm_check_next_free_slot (heap , i , p );
2025
2120
} else {
2026
- q = & p -> next_free_slot ;
2027
- p = * q ;
2121
+ q = p ;
2122
+ if (q == (zend_mm_free_slot * )& heap -> free_slot [i ]) {
2123
+ p = q -> next_free_slot ;
2124
+ } else {
2125
+ p = zend_mm_check_next_free_slot (heap , i , q );
2126
+ }
2028
2127
}
2029
2128
}
2030
2129
}
@@ -2376,6 +2475,18 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
2376
2475
memset (p -> free_map , 0 , sizeof (p -> free_map ) + sizeof (p -> map ));
2377
2476
p -> free_map [0 ] = (1L << ZEND_MM_FIRST_PAGE ) - 1 ;
2378
2477
p -> map [0 ] = ZEND_MM_LRUN (ZEND_MM_FIRST_PAGE );
2478
+
2479
+ pid_t pid = getpid ();
2480
+ if (heap -> pid != pid ) {
2481
+ if (zend_mm_init_key (heap ) != SUCCESS ) {
2482
+ zend_mm_panic ("Can't initialize heap" );
2483
+ }
2484
+ heap -> pid = pid ;
2485
+ } else {
2486
+ if (zend_mm_refresh_key (heap ) != SUCCESS ) {
2487
+ zend_mm_panic ("Can't initialize heap" );
2488
+ }
2489
+ }
2379
2490
}
2380
2491
}
2381
2492
@@ -3052,6 +3163,12 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
3052
3163
heap -> size = 0 ;
3053
3164
heap -> peak = 0 ;
3054
3165
#endif
3166
+ if (zend_mm_init_key (heap ) != SUCCESS ) {
3167
+ #if ZEND_MM_ERROR
3168
+ fprintf (stderr , "Can't initialize heap\n" );
3169
+ #endif
3170
+ return NULL ;
3171
+ }
3055
3172
#if ZEND_MM_LIMIT
3056
3173
heap -> limit = (size_t )Z_L (-1 ) >> 1 ;
3057
3174
heap -> overflow = 0 ;
@@ -3076,6 +3193,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
3076
3193
memcpy (storage -> data , data , data_size );
3077
3194
}
3078
3195
heap -> storage = storage ;
3196
+ heap -> pid = getpid ();
3079
3197
return heap ;
3080
3198
#else
3081
3199
return NULL ;
0 commit comments