Coverage Report

Created: 2026-06-02 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/zend_shared_alloc.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend OPcache                                                         |
4
   +----------------------------------------------------------------------+
5
   | Copyright © The PHP Group and Contributors.                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to the Modified BSD License that is      |
8
   | bundled with this package in the file LICENSE, and is available      |
9
   | through the World Wide Web at <https://www.php.net/license/>.        |
10
   |                                                                      |
11
   | SPDX-License-Identifier: BSD-3-Clause                                |
12
   +----------------------------------------------------------------------+
13
   | Authors: Andi Gutmans <andi@php.net>                                 |
14
   |          Zeev Suraski <zeev@php.net>                                 |
15
   |          Stanislav Malyshev <stas@zend.com>                          |
16
   |          Dmitry Stogov <dmitry@php.net>                              |
17
   +----------------------------------------------------------------------+
18
*/
19
20
#if defined(__linux__) && defined(HAVE_MEMFD_CREATE)
21
# ifndef _GNU_SOURCE
22
#  define _GNU_SOURCE
23
# endif
24
# include <sys/mman.h>
25
#endif
26
27
#include <errno.h>
28
#include "ZendAccelerator.h"
29
#include "zend_shared_alloc.h"
30
#ifdef HAVE_UNISTD_H
31
# include <unistd.h>
32
#endif
33
#include <fcntl.h>
34
#ifndef ZEND_WIN32
35
# include <sys/types.h>
36
# include <signal.h>
37
# include <sys/stat.h>
38
# include <stdio.h>
39
#endif
40
41
#ifdef HAVE_MPROTECT
42
# include "sys/mman.h"
43
#endif
44
45
0
#define SEM_FILENAME_PREFIX ".ZendSem."
46
6
#define S_H(s) g_shared_alloc_handler->s
47
48
/* True globals */
49
/* old/new mapping. We can use true global even for ZTS because its usage
50
   is wrapped with exclusive lock anyway */
51
static const zend_shared_memory_handlers *g_shared_alloc_handler = NULL;
52
static const char *g_shared_model;
53
/* pointer to globals allocated in SHM and shared across processes */
54
ZEND_EXT_API zend_smm_shared_globals *smm_shared_globals;
55
56
#ifndef ZEND_WIN32
57
#ifdef ZTS
58
static MUTEX_T zts_lock;
59
#endif
60
int lock_file = -1;
61
static char lockfile_name[MAXPATHLEN];
62
#endif
63
64
static const zend_shared_memory_handler_entry handler_table[] = {
65
#ifdef USE_MMAP
66
  { "mmap", &zend_alloc_mmap_handlers },
67
#endif
68
#ifdef USE_SHM
69
  { "shm", &zend_alloc_shm_handlers },
70
#endif
71
#ifdef USE_SHM_OPEN
72
  { "posix", &zend_alloc_posix_handlers },
73
#endif
74
#ifdef ZEND_WIN32
75
  { "win32", &zend_alloc_win32_handlers },
76
#endif
77
  { NULL, NULL}
78
};
79
80
#ifndef ZEND_WIN32
81
void zend_shared_alloc_create_lock(char *lockfile_path)
82
2
{
83
2
  int val;
84
85
#ifdef ZTS
86
  zts_lock = tsrm_mutex_alloc();
87
#endif
88
89
2
#if defined(__linux__) && defined(HAVE_MEMFD_CREATE)
90
  /* on Linux, we can use a memfd instead of a "real" file, so
91
   * we can do this without a writable filesystem and without
92
   * needing to clean up */
93
  /* note: FreeBSD has memfd_create(), too, but fcntl(F_SETLKW)
94
   * on it fails with EBADF, therefore we use this only on
95
   * Linux */
96
2
  lock_file = memfd_create("opcache_lock", MFD_CLOEXEC);
97
2
  if (lock_file >= 0)
98
2
    return;
99
0
#endif
100
101
0
#ifdef O_TMPFILE
102
0
  lock_file = open(lockfile_path, O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, 0666);
103
  /* lack of O_TMPFILE support results in many possible errors
104
   * use it only when open returns a non-negative integer */
105
0
  if (lock_file >= 0) {
106
0
    return;
107
0
  }
108
0
#endif
109
110
0
  snprintf(lockfile_name, sizeof(lockfile_name), "%s/%sXXXXXX", lockfile_path, SEM_FILENAME_PREFIX);
111
0
  lock_file = mkstemp(lockfile_name);
112
0
  if (lock_file == -1) {
113
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Unable to create opcache lock file in %s: %s (%d)", lockfile_path, strerror(errno), errno);
114
0
  }
115
116
0
  if (fchmod(lock_file, 0666) == -1) {
117
0
    zend_accel_error(ACCEL_LOG_WARNING, "Unable to change opcache lock file permissions in %s: %s (%d)", lockfile_path, strerror(errno), errno);
118
0
  }
119
120
0
  val = fcntl(lock_file, F_GETFD, 0);
121
0
  val |= FD_CLOEXEC;
122
0
  fcntl(lock_file, F_SETFD, val);
123
124
0
  unlink(lockfile_name);
125
0
}
126
#endif
127
128
static void no_memory_bailout(size_t allocate_size, const char *error)
129
0
{
130
0
  zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Unable to allocate shared memory segment of %zu bytes: %s: %s (%d)", allocate_size, error?error:"unknown", strerror(errno), errno );
131
0
}
132
133
static void copy_shared_segments(void *to, void *from, int count, int size)
134
2
{
135
2
  zend_shared_segment **shared_segments_v = (zend_shared_segment **)to;
136
2
  void *shared_segments_to_p = ((char *)to + count*(sizeof(void *)));
137
2
  void *shared_segments_from_p = from;
138
2
  int i;
139
140
4
  for (i = 0; i < count; i++) {
141
2
    shared_segments_v[i] =  shared_segments_to_p;
142
2
    memcpy(shared_segments_to_p, shared_segments_from_p, size);
143
2
    shared_segments_to_p = ((char *)shared_segments_to_p + size);
144
2
    shared_segments_from_p = ((char *)shared_segments_from_p + size);
145
2
  }
146
2
}
147
148
static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, const char **error_in)
149
2
{
150
2
  int res;
151
2
  g_shared_alloc_handler = he->handler;
152
2
  g_shared_model = he->name;
153
2
  ZSMMG(shared_segments) = NULL;
154
2
  ZSMMG(shared_segments_count) = 0;
155
156
2
  res = S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in);
157
158
2
  if (res) {
159
    /* this model works! */
160
2
    return res;
161
2
  }
162
0
  if (*shared_segments_p) {
163
0
    int i;
164
    /* cleanup */
165
0
    for (i = 0; i < *shared_segments_count; i++) {
166
0
      if ((*shared_segments_p)[i]->p && (*shared_segments_p)[i]->p != (void *)-1) {
167
0
        S_H(detach_segment)((*shared_segments_p)[i]);
168
0
      }
169
0
    }
170
0
    free(*shared_segments_p);
171
0
    *shared_segments_p = NULL;
172
0
  }
173
0
  g_shared_alloc_handler = NULL;
174
0
  return ALLOC_FAILURE;
175
2
}
176
177
int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size)
178
2
{
179
2
  zend_shared_segment **tmp_shared_segments;
180
2
  size_t shared_segments_array_size;
181
2
  zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals;
182
2
  const char *error_in = NULL;
183
2
  const zend_shared_memory_handler_entry *he;
184
2
  int res = ALLOC_FAILURE;
185
2
  int i;
186
187
  /* shared_free must be valid before we call zend_shared_alloc()
188
   * - make it temporarily point to a local variable
189
   */
190
2
  smm_shared_globals = &tmp_shared_globals;
191
2
  ZSMMG(shared_free) = requested_size - reserved_size; /* goes to tmp_shared_globals.shared_free */
192
193
2
#ifndef ZEND_WIN32
194
2
  zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path);
195
#else
196
  zend_shared_alloc_create_lock();
197
#endif
198
199
2
  if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) {
200
0
    const char *model = ZCG(accel_directives).memory_model;
201
    /* "cgi" is really "shm"... */
202
0
    if (strncmp(ZCG(accel_directives).memory_model, "cgi", sizeof("cgi")) == 0) {
203
0
      model = "shm";
204
0
    }
205
206
0
    for (he = handler_table; he->name; he++) {
207
0
      if (strcmp(model, he->name) == 0) {
208
0
        res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
209
0
        if (res) {
210
          /* this model works! */
211
0
          break;
212
0
        }
213
0
      }
214
0
    }
215
0
  }
216
217
2
  if (res == FAILED_REATTACHED) {
218
0
    smm_shared_globals = NULL;
219
0
    return res;
220
0
  }
221
#if ENABLE_FILE_CACHE_FALLBACK
222
  if (ALLOC_FALLBACK == res) {
223
    smm_shared_globals = NULL;
224
    return ALLOC_FALLBACK;
225
  }
226
#endif
227
228
2
  if (!g_shared_alloc_handler) {
229
    /* try memory handlers in order */
230
2
    if (handler_table->name == NULL) {
231
0
      return NO_SHM_BACKEND;
232
0
    }
233
2
    for (he = handler_table; he->name; he++) {
234
2
      res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
235
2
      if (res) {
236
        /* this model works! */
237
2
        break;
238
2
      }
239
2
    }
240
2
  }
241
242
2
  if (!g_shared_alloc_handler) {
243
0
    no_memory_bailout(requested_size, error_in);
244
0
    return ALLOC_FAILURE;
245
0
  }
246
247
2
  if (res == SUCCESSFULLY_REATTACHED) {
248
0
    return res;
249
0
  }
250
#if ENABLE_FILE_CACHE_FALLBACK
251
  if (ALLOC_FALLBACK == res) {
252
    smm_shared_globals = NULL;
253
    return ALLOC_FALLBACK;
254
  }
255
#endif
256
257
4
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
258
2
    ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size;
259
2
  }
260
261
2
  shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)();
262
263
  /* move shared_segments and shared_free to shared memory */
264
2
  ZCG(locked) = 1; /* no need to perform a real lock at this point */
265
266
2
  p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals));
267
2
  if (!p_tmp_shared_globals) {
268
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
269
0
    return ALLOC_FAILURE;
270
0
  }
271
2
  memset(p_tmp_shared_globals, 0, sizeof(zend_smm_shared_globals));
272
273
2
  tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *));
274
2
  if (!tmp_shared_segments) {
275
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
276
0
    return ALLOC_FAILURE;
277
0
  }
278
279
2
  copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
280
281
2
  *p_tmp_shared_globals = tmp_shared_globals;
282
2
  smm_shared_globals = p_tmp_shared_globals;
283
284
2
  free(ZSMMG(shared_segments));
285
2
  ZSMMG(shared_segments) = tmp_shared_segments;
286
287
2
  ZSMMG(shared_memory_state).positions = (size_t *)zend_shared_alloc(sizeof(size_t) * ZSMMG(shared_segments_count));
288
2
  if (!ZSMMG(shared_memory_state).positions) {
289
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
290
0
    return ALLOC_FAILURE;
291
0
  }
292
293
2
  if (reserved_size) {
294
0
    i = ZSMMG(shared_segments_count) - 1;
295
0
    if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= reserved_size) {
296
0
      ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size - reserved_size;
297
0
      ZSMMG(reserved) = (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end;
298
0
      ZSMMG(reserved_size) = reserved_size;
299
0
    } else {
300
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
301
0
      return ALLOC_FAILURE;
302
0
    }
303
0
  }
304
305
2
  ZCG(locked) = 0;
306
307
2
  return res;
308
2
}
309
310
void zend_shared_alloc_shutdown(void)
311
0
{
312
0
  zend_shared_segment **tmp_shared_segments;
313
0
  zend_shared_segment *shared_segments_buf[16];
314
0
  size_t shared_segments_array_size;
315
0
  zend_smm_shared_globals tmp_shared_globals;
316
0
  int i;
317
318
0
  tmp_shared_globals = *smm_shared_globals;
319
0
  smm_shared_globals = &tmp_shared_globals;
320
0
  shared_segments_array_size = ZSMMG(shared_segments_count) * (S_H(segment_type_size)() + sizeof(void *));
321
0
  if (shared_segments_array_size > 16) {
322
0
    tmp_shared_segments = malloc(shared_segments_array_size);
323
0
  } else {
324
0
    tmp_shared_segments = shared_segments_buf;
325
0
  }
326
0
  copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
327
0
  ZSMMG(shared_segments) = tmp_shared_segments;
328
329
0
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
330
0
    S_H(detach_segment)(ZSMMG(shared_segments)[i]);
331
0
  }
332
0
  if (shared_segments_array_size > 16) {
333
0
    free(ZSMMG(shared_segments));
334
0
  }
335
0
  ZSMMG(shared_segments) = NULL;
336
0
  g_shared_alloc_handler = NULL;
337
0
#ifndef ZEND_WIN32
338
0
  close(lock_file);
339
340
# ifdef ZTS
341
  tsrm_mutex_free(zts_lock);
342
# endif
343
0
#endif
344
0
}
345
346
static size_t zend_shared_alloc_get_largest_free_block(void)
347
0
{
348
0
  int i;
349
0
  size_t largest_block_size = 0;
350
351
0
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
352
0
    size_t block_size = ZSMMG(shared_segments)[i]->end - ZSMMG(shared_segments)[i]->pos;
353
354
0
    if (block_size>largest_block_size) {
355
0
      largest_block_size = block_size;
356
0
    }
357
0
  }
358
0
  return largest_block_size;
359
0
}
360
361
0
#define MIN_FREE_MEMORY 64*1024
362
363
0
#define SHARED_ALLOC_FAILED() do {   \
364
0
    zend_accel_error(ACCEL_LOG_WARNING, "Not enough free shared space to allocate %zu bytes (%zu bytes free)", size, ZSMMG(shared_free)); \
365
0
    if (zend_shared_alloc_get_largest_free_block() < MIN_FREE_MEMORY) { \
366
0
      ZSMMG(memory_exhausted) = 1; \
367
0
    } \
368
0
  } while (0)
369
370
void *zend_shared_alloc(size_t size)
371
27.4k
{
372
27.4k
  int i;
373
27.4k
  size_t block_size = ZEND_ALIGNED_SIZE(size);
374
375
27.4k
#if 1
376
27.4k
  if (!ZCG(locked)) {
377
0
    ZEND_ASSERT(0 && "Shared memory lock not obtained");
378
0
    zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Shared memory lock not obtained");
379
0
  }
380
27.4k
#endif
381
27.4k
  if (block_size > ZSMMG(shared_free)) { /* No hope to find a big-enough block */
382
0
    SHARED_ALLOC_FAILED();
383
0
    return NULL;
384
0
  }
385
27.4k
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
386
27.4k
    if (ZSMMG(shared_segments)[i]->end - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
387
27.4k
      void *retval = (void *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);
388
389
27.4k
      ZSMMG(shared_segments)[i]->pos += block_size;
390
27.4k
      ZSMMG(shared_free) -= block_size;
391
27.4k
      ZEND_ASSERT(((uintptr_t)retval & 0x7) == 0); /* should be 8 byte aligned */
392
27.4k
      return retval;
393
27.4k
    }
394
27.4k
  }
395
0
  SHARED_ALLOC_FAILED();
396
0
  return NULL;
397
27.4k
}
398
399
static zend_always_inline zend_ulong zend_rotr3(zend_ulong key)
400
794k
{
401
794k
  return (key >> 3) | (key << ((sizeof(key) * 8) - 3));
402
794k
}
403
404
int zend_shared_memdup_size(void *source, size_t size)
405
95.7k
{
406
95.7k
  void *old_p;
407
95.7k
  zend_ulong key = (zend_ulong)source;
408
409
95.7k
  key = zend_rotr3(key);
410
95.7k
  if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) != NULL) {
411
    /* we already duplicated this pointer */
412
36.8k
    return 0;
413
36.8k
  }
414
58.8k
  zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, source);
415
58.8k
  return ZEND_ALIGNED_SIZE(size);
416
95.7k
}
417
418
static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, bool get_xlat, bool set_xlat, bool free_source)
419
347k
{
420
347k
  void *old_p, *retval;
421
347k
  zend_ulong key;
422
423
347k
  if (get_xlat) {
424
0
    key = (zend_ulong)source;
425
0
    key = zend_rotr3(key);
426
0
    if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) != NULL) {
427
      /* we already duplicated this pointer */
428
0
      return old_p;
429
0
    }
430
0
  }
431
347k
  retval = ZCG(mem);
432
347k
  ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
433
347k
  memcpy(retval, source, size);
434
347k
  if (set_xlat) {
435
289k
    if (!get_xlat) {
436
289k
      key = (zend_ulong)source;
437
289k
      key = zend_rotr3(key);
438
289k
    }
439
289k
    zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, retval);
440
289k
  }
441
347k
  if (free_source) {
442
135k
    efree(source);
443
135k
  }
444
347k
  return retval;
445
347k
}
446
447
void *zend_shared_memdup_get_put_free(void *source, size_t size)
448
0
{
449
0
  return _zend_shared_memdup(source, size, true, true, true);
450
0
}
451
452
void *zend_shared_memdup_put_free(void *source, size_t size)
453
90.5k
{
454
90.5k
  return _zend_shared_memdup(source, size, false, true, true);
455
90.5k
}
456
457
void *zend_shared_memdup_free(void *source, size_t size)
458
44.7k
{
459
44.7k
  return _zend_shared_memdup(source, size, false, false, true);
460
44.7k
}
461
462
void *zend_shared_memdup_get_put(void *source, size_t size)
463
0
{
464
0
  return _zend_shared_memdup(source, size, true, true, false);
465
0
}
466
467
void *zend_shared_memdup_put(void *source, size_t size)
468
198k
{
469
198k
  return _zend_shared_memdup(source, size, false, true, false);
470
198k
}
471
472
void *zend_shared_memdup(void *source, size_t size)
473
13.6k
{
474
13.6k
  return _zend_shared_memdup(source, size, false, false, false);
475
13.6k
}
476
477
void zend_shared_alloc_safe_unlock(void)
478
44.4k
{
479
44.4k
  if (ZCG(locked)) {
480
0
    zend_shared_alloc_unlock();
481
0
  }
482
44.4k
}
483
484
void zend_shared_alloc_lock(void)
485
53.3k
{
486
53.3k
  ZEND_ASSERT(!ZCG(locked));
487
488
53.3k
#ifndef ZEND_WIN32
489
53.3k
  struct flock mem_write_lock;
490
491
53.3k
  mem_write_lock.l_type = F_WRLCK;
492
53.3k
  mem_write_lock.l_whence = SEEK_SET;
493
53.3k
  mem_write_lock.l_start = 0;
494
53.3k
  mem_write_lock.l_len = 1;
495
496
#ifdef ZTS
497
  tsrm_mutex_lock(zts_lock);
498
#endif
499
500
#if 0
501
  /* this will happen once per process, and will un-globalize mem_write_lock */
502
  if (mem_write_lock.l_pid == -1) {
503
    mem_write_lock.l_pid = getpid();
504
  }
505
#endif
506
507
53.3k
  while (1) {
508
53.3k
    if (fcntl(lock_file, F_SETLKW, &mem_write_lock) == -1) {
509
0
      if (errno == EINTR) {
510
0
        continue;
511
0
      }
512
0
      zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot create lock - %s (%d)", strerror(errno), errno);
513
0
    }
514
53.3k
    break;
515
53.3k
  }
516
#else
517
  zend_shared_alloc_lock_win32();
518
#endif
519
520
53.3k
  ZCG(locked) = 1;
521
53.3k
}
522
523
void zend_shared_alloc_unlock(void)
524
53.3k
{
525
53.3k
  ZEND_ASSERT(ZCG(locked));
526
527
53.3k
#ifndef ZEND_WIN32
528
53.3k
  struct flock mem_write_unlock;
529
530
53.3k
  mem_write_unlock.l_type = F_UNLCK;
531
53.3k
  mem_write_unlock.l_whence = SEEK_SET;
532
53.3k
  mem_write_unlock.l_start = 0;
533
53.3k
  mem_write_unlock.l_len = 1;
534
53.3k
#endif
535
536
53.3k
  ZCG(locked) = 0;
537
538
53.3k
#ifndef ZEND_WIN32
539
53.3k
  if (fcntl(lock_file, F_SETLK, &mem_write_unlock) == -1) {
540
0
    zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot remove lock - %s (%d)", strerror(errno), errno);
541
0
  }
542
#ifdef ZTS
543
  tsrm_mutex_unlock(zts_lock);
544
#endif
545
#else
546
  zend_shared_alloc_unlock_win32();
547
#endif
548
53.3k
}
549
550
void zend_shared_alloc_init_xlat_table(void)
551
27.4k
{
552
  /* Prepare translation table */
553
27.4k
  zend_hash_init(&ZCG(xlat_table), 128, NULL, NULL, 0);
554
27.4k
}
555
556
void zend_shared_alloc_destroy_xlat_table(void)
557
27.4k
{
558
  /* Destroy translation table */
559
27.4k
  zend_hash_destroy(&ZCG(xlat_table));
560
27.4k
}
561
562
void zend_shared_alloc_clear_xlat_table(void)
563
27.4k
{
564
27.4k
  zend_hash_clean(&ZCG(xlat_table));
565
27.4k
}
566
567
uint32_t zend_shared_alloc_checkpoint_xlat_table(void)
568
0
{
569
0
  return ZCG(xlat_table).nNumUsed;
570
0
}
571
572
void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint)
573
0
{
574
0
  zend_hash_discard(&ZCG(xlat_table), checkpoint);
575
0
}
576
577
void zend_shared_alloc_register_xlat_entry(const void *key_pointer, const void *value)
578
116k
{
579
116k
  zend_ulong key = (zend_ulong)key_pointer;
580
581
116k
  key = zend_rotr3(key);
582
116k
  zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, (void*)value);
583
116k
}
584
585
void *zend_shared_alloc_get_xlat_entry(const void *key_pointer)
586
293k
{
587
293k
  void *retval;
588
293k
  zend_ulong key = (zend_ulong)key_pointer;
589
590
293k
  key = zend_rotr3(key);
591
293k
  if ((retval = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) == NULL) {
592
207k
    return NULL;
593
207k
  }
594
85.7k
  return retval;
595
293k
}
596
597
size_t zend_shared_alloc_get_free_memory(void)
598
24
{
599
24
  return ZSMMG(shared_free);
600
24
}
601
602
void zend_shared_alloc_save_state(void)
603
2
{
604
2
  int i;
605
606
4
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
607
2
    ZSMMG(shared_memory_state).positions[i] = ZSMMG(shared_segments)[i]->pos;
608
2
  }
609
2
  ZSMMG(shared_memory_state).shared_free = ZSMMG(shared_free);
610
2
}
611
612
void zend_shared_alloc_restore_state(void)
613
0
{
614
0
  int i;
615
616
0
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
617
0
    ZSMMG(shared_segments)[i]->pos = ZSMMG(shared_memory_state).positions[i];
618
0
  }
619
0
  ZSMMG(shared_free) = ZSMMG(shared_memory_state).shared_free;
620
0
  ZSMMG(memory_exhausted) = 0;
621
0
  ZSMMG(wasted_shared_memory) = 0;
622
0
}
623
624
const char *zend_accel_get_shared_model(void)
625
3
{
626
3
  return g_shared_model;
627
3
}
628
629
void zend_accel_shared_protect(bool protected)
630
349k
{
631
349k
#ifdef HAVE_MPROTECT
632
349k
  int i;
633
634
349k
  if (!smm_shared_globals) {
635
0
    return;
636
0
  }
637
638
349k
  const int mode = protected ? PROT_READ : PROT_READ|PROT_WRITE;
639
640
699k
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
641
349k
    mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode);
642
349k
  }
643
#elif defined(ZEND_WIN32)
644
  int i;
645
646
  if (!smm_shared_globals) {
647
    return;
648
  }
649
650
  const int mode = protected ? PAGE_READONLY : PAGE_READWRITE;
651
652
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
653
    DWORD oldProtect;
654
    if (!VirtualProtect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode, &oldProtect)) {
655
      zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Failed to protect memory");
656
    }
657
  }
658
#endif
659
349k
}
660
661
bool zend_accel_in_shm(void *ptr)
662
36.4k
{
663
36.4k
  int i;
664
665
36.4k
  if (!smm_shared_globals) {
666
0
    return false;
667
0
  }
668
669
71.9k
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
670
36.4k
    if ((char*)ptr >= (char*)ZSMMG(shared_segments)[i]->p &&
671
956
        (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end) {
672
956
      return true;
673
956
    }
674
36.4k
  }
675
35.5k
  return false;
676
36.4k
}