Coverage Report

Created: 2026-06-13 07:01

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
48
#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
16
{
83
16
  int val;
84
85
#ifdef ZTS
86
  zts_lock = tsrm_mutex_alloc();
87
#endif
88
89
16
#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
16
  lock_file = memfd_create("opcache_lock", MFD_CLOEXEC);
97
16
  if (lock_file >= 0)
98
16
    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
16
{
135
16
  zend_shared_segment **shared_segments_v = (zend_shared_segment **)to;
136
16
  void *shared_segments_to_p = ((char *)to + count*(sizeof(void *)));
137
16
  void *shared_segments_from_p = from;
138
16
  int i;
139
140
32
  for (i = 0; i < count; i++) {
141
16
    shared_segments_v[i] =  shared_segments_to_p;
142
16
    memcpy(shared_segments_to_p, shared_segments_from_p, size);
143
16
    shared_segments_to_p = ((char *)shared_segments_to_p + size);
144
16
    shared_segments_from_p = ((char *)shared_segments_from_p + size);
145
16
  }
146
16
}
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
16
{
150
16
  int res;
151
16
  g_shared_alloc_handler = he->handler;
152
16
  g_shared_model = he->name;
153
16
  ZSMMG(shared_segments) = NULL;
154
16
  ZSMMG(shared_segments_count) = 0;
155
156
16
  res = S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in);
157
158
16
  if (res) {
159
    /* this model works! */
160
16
    return res;
161
16
  }
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
16
}
176
177
int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size)
178
16
{
179
16
  zend_shared_segment **tmp_shared_segments;
180
16
  size_t shared_segments_array_size;
181
16
  zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals;
182
16
  const char *error_in = NULL;
183
16
  const zend_shared_memory_handler_entry *he;
184
16
  int res = ALLOC_FAILURE;
185
16
  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
16
  smm_shared_globals = &tmp_shared_globals;
191
16
  ZSMMG(shared_free) = requested_size - reserved_size; /* goes to tmp_shared_globals.shared_free */
192
193
16
#ifndef ZEND_WIN32
194
16
  zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path);
195
#else
196
  zend_shared_alloc_create_lock();
197
#endif
198
199
16
  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
16
  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
16
  if (!g_shared_alloc_handler) {
229
    /* try memory handlers in order */
230
16
    if (handler_table->name == NULL) {
231
0
      return NO_SHM_BACKEND;
232
0
    }
233
16
    for (he = handler_table; he->name; he++) {
234
16
      res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
235
16
      if (res) {
236
        /* this model works! */
237
16
        break;
238
16
      }
239
16
    }
240
16
  }
241
242
16
  if (!g_shared_alloc_handler) {
243
0
    no_memory_bailout(requested_size, error_in);
244
0
    return ALLOC_FAILURE;
245
0
  }
246
247
16
  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
32
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
258
16
    ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size;
259
16
  }
260
261
16
  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
16
  ZCG(locked) = 1; /* no need to perform a real lock at this point */
265
266
16
  p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals));
267
16
  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
16
  memset(p_tmp_shared_globals, 0, sizeof(zend_smm_shared_globals));
272
273
16
  tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *));
274
16
  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
16
  copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
280
281
16
  *p_tmp_shared_globals = tmp_shared_globals;
282
16
  smm_shared_globals = p_tmp_shared_globals;
283
284
16
  free(ZSMMG(shared_segments));
285
16
  ZSMMG(shared_segments) = tmp_shared_segments;
286
287
16
  ZSMMG(shared_memory_state).positions = (size_t *)zend_shared_alloc(sizeof(size_t) * ZSMMG(shared_segments_count));
288
16
  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
16
  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
16
  ZCG(locked) = 0;
306
307
16
  return res;
308
16
}
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
53.3k
{
372
53.3k
  int i;
373
53.3k
  size_t block_size = ZEND_ALIGNED_SIZE(size);
374
375
53.3k
#if 1
376
53.3k
  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
53.3k
#endif
381
53.3k
  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
53.3k
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
386
53.3k
    if (ZSMMG(shared_segments)[i]->end - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
387
53.3k
      void *retval = (void *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);
388
389
53.3k
      ZSMMG(shared_segments)[i]->pos += block_size;
390
53.3k
      ZSMMG(shared_free) -= block_size;
391
53.3k
      ZEND_ASSERT(((uintptr_t)retval & 0x7) == 0); /* should be 8 byte aligned */
392
53.3k
      return retval;
393
53.3k
    }
394
53.3k
  }
395
0
  SHARED_ALLOC_FAILED();
396
0
  return NULL;
397
53.3k
}
398
399
static zend_always_inline zend_ulong zend_rotr3(zend_ulong key)
400
1.60M
{
401
1.60M
  return (key >> 3) | (key << ((sizeof(key) * 8) - 3));
402
1.60M
}
403
404
int zend_shared_memdup_size(void *source, size_t size)
405
198k
{
406
198k
  void *old_p;
407
198k
  zend_ulong key = (zend_ulong)source;
408
409
198k
  key = zend_rotr3(key);
410
198k
  if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) != NULL) {
411
    /* we already duplicated this pointer */
412
75.1k
    return 0;
413
75.1k
  }
414
122k
  zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, source);
415
122k
  return ZEND_ALIGNED_SIZE(size);
416
198k
}
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
698k
{
420
698k
  void *old_p, *retval;
421
698k
  zend_ulong key;
422
423
698k
  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
698k
  retval = ZCG(mem);
432
698k
  ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
433
698k
  memcpy(retval, source, size);
434
698k
  if (set_xlat) {
435
584k
    if (!get_xlat) {
436
584k
      key = (zend_ulong)source;
437
584k
      key = zend_rotr3(key);
438
584k
    }
439
584k
    zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, retval);
440
584k
  }
441
698k
  if (free_source) {
442
273k
    efree(source);
443
273k
  }
444
698k
  return retval;
445
698k
}
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
186k
{
454
186k
  return _zend_shared_memdup(source, size, false, true, true);
455
186k
}
456
457
void *zend_shared_memdup_free(void *source, size_t size)
458
87.4k
{
459
87.4k
  return _zend_shared_memdup(source, size, false, false, true);
460
87.4k
}
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
398k
{
469
398k
  return _zend_shared_memdup(source, size, false, true, false);
470
398k
}
471
472
void *zend_shared_memdup(void *source, size_t size)
473
26.3k
{
474
26.3k
  return _zend_shared_memdup(source, size, false, false, false);
475
26.3k
}
476
477
void zend_shared_alloc_safe_unlock(void)
478
229k
{
479
229k
  if (ZCG(locked)) {
480
0
    zend_shared_alloc_unlock();
481
0
  }
482
229k
}
483
484
void zend_shared_alloc_lock(void)
485
103k
{
486
103k
  ZEND_ASSERT(!ZCG(locked));
487
488
103k
#ifndef ZEND_WIN32
489
103k
  struct flock mem_write_lock;
490
491
103k
  mem_write_lock.l_type = F_WRLCK;
492
103k
  mem_write_lock.l_whence = SEEK_SET;
493
103k
  mem_write_lock.l_start = 0;
494
103k
  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
103k
  while (1) {
508
103k
    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
103k
    break;
515
103k
  }
516
#else
517
  zend_shared_alloc_lock_win32();
518
#endif
519
520
103k
  ZCG(locked) = 1;
521
103k
}
522
523
void zend_shared_alloc_unlock(void)
524
103k
{
525
103k
  ZEND_ASSERT(ZCG(locked));
526
527
103k
#ifndef ZEND_WIN32
528
103k
  struct flock mem_write_unlock;
529
530
103k
  mem_write_unlock.l_type = F_UNLCK;
531
103k
  mem_write_unlock.l_whence = SEEK_SET;
532
103k
  mem_write_unlock.l_start = 0;
533
103k
  mem_write_unlock.l_len = 1;
534
103k
#endif
535
536
103k
  ZCG(locked) = 0;
537
538
103k
#ifndef ZEND_WIN32
539
103k
  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
103k
}
549
550
void zend_shared_alloc_init_xlat_table(void)
551
53.2k
{
552
  /* Prepare translation table */
553
53.2k
  zend_hash_init(&ZCG(xlat_table), 128, NULL, NULL, 0);
554
53.2k
}
555
556
void zend_shared_alloc_destroy_xlat_table(void)
557
53.2k
{
558
  /* Destroy translation table */
559
53.2k
  zend_hash_destroy(&ZCG(xlat_table));
560
53.2k
}
561
562
void zend_shared_alloc_clear_xlat_table(void)
563
53.2k
{
564
53.2k
  zend_hash_clean(&ZCG(xlat_table));
565
53.2k
}
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
230k
{
579
230k
  zend_ulong key = (zend_ulong)key_pointer;
580
581
230k
  key = zend_rotr3(key);
582
230k
  zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, (void*)value);
583
230k
}
584
585
void *zend_shared_alloc_get_xlat_entry(const void *key_pointer)
586
593k
{
587
593k
  void *retval;
588
593k
  zend_ulong key = (zend_ulong)key_pointer;
589
590
593k
  key = zend_rotr3(key);
591
593k
  if ((retval = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) == NULL) {
592
419k
    return NULL;
593
419k
  }
594
173k
  return retval;
595
593k
}
596
597
size_t zend_shared_alloc_get_free_memory(void)
598
50
{
599
50
  return ZSMMG(shared_free);
600
50
}
601
602
void zend_shared_alloc_save_state(void)
603
16
{
604
16
  int i;
605
606
32
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
607
16
    ZSMMG(shared_memory_state).positions[i] = ZSMMG(shared_segments)[i]->pos;
608
16
  }
609
16
  ZSMMG(shared_memory_state).shared_free = ZSMMG(shared_free);
610
16
}
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
4
{
626
4
  return g_shared_model;
627
4
}
628
629
void zend_accel_shared_protect(bool protected)
630
693k
{
631
693k
#ifdef HAVE_MPROTECT
632
693k
  int i;
633
634
693k
  if (!smm_shared_globals) {
635
0
    return;
636
0
  }
637
638
693k
  const int mode = protected ? PROT_READ : PROT_READ|PROT_WRITE;
639
640
1.38M
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
641
693k
    mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode);
642
693k
  }
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
693k
}
660
661
bool zend_accel_in_shm(void *ptr)
662
74.1k
{
663
74.1k
  int i;
664
665
74.1k
  if (!smm_shared_globals) {
666
0
    return false;
667
0
  }
668
669
146k
  for (i = 0; i < ZSMMG(shared_segments_count); i++) {
670
74.1k
    if ((char*)ptr >= (char*)ZSMMG(shared_segments)[i]->p &&
671
38.2k
        (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end) {
672
1.75k
      return true;
673
1.75k
    }
674
74.1k
  }
675
72.4k
  return false;
676
74.1k
}