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