Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/shared_alloc_shm.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend OPcache                                                         |
4
   +----------------------------------------------------------------------+
5
   | Copyright (c) The PHP Group                                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to version 3.01 of the PHP license,      |
8
   | that is bundled with this package in the file LICENSE, and is        |
9
   | available through the world-wide-web at the following url:           |
10
   | https://www.php.net/license/3_01.txt                                 |
11
   | If you did not receive a copy of the PHP license and are unable to   |
12
   | obtain it through the world-wide-web, please send a note to          |
13
   | license@php.net so we can mail you a copy immediately.               |
14
   +----------------------------------------------------------------------+
15
   | Authors: Andi Gutmans <andi@php.net>                                 |
16
   |          Zeev Suraski <zeev@php.net>                                 |
17
   |          Stanislav Malyshev <stas@zend.com>                          |
18
   |          Dmitry Stogov <dmitry@php.net>                              |
19
   +----------------------------------------------------------------------+
20
*/
21
22
#include "zend_shared_alloc.h"
23
24
#ifdef USE_SHM
25
26
#if defined(__FreeBSD__)
27
# include <machine/param.h>
28
#endif
29
#include <sys/types.h>
30
#include <sys/shm.h>
31
#include <sys/ipc.h>
32
#include <signal.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <unistd.h>
36
#include <errno.h>
37
38
#include <sys/stat.h>
39
#include <fcntl.h>
40
41
#ifndef MIN
42
# define MIN(x, y) ((x) > (y)? (y) : (x))
43
#endif
44
45
0
#define SEG_ALLOC_SIZE_MIN 2*1024*1024
46
47
typedef struct  {
48
    zend_shared_segment common;
49
    int shm_id;
50
} zend_shared_segment_shm;
51
52
static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, const char **error_in)
53
0
{
54
0
  int i;
55
0
  size_t allocate_size = 0, remaining_bytes, seg_allocate_size;
56
0
  int first_segment_id = -1;
57
0
  key_t first_segment_key = -1;
58
0
  struct shmid_ds sds;
59
0
  int shmget_flags;
60
0
  zend_shared_segment_shm *shared_segments;
61
62
0
  shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL;
63
64
  /* Try contiguous allocation first. */
65
0
  seg_allocate_size = requested_size;
66
0
  first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags);
67
0
  if (UNEXPECTED(first_segment_id == -1)) {
68
    /* Search for biggest n^2 < requested_size. */
69
0
    seg_allocate_size = SEG_ALLOC_SIZE_MIN;
70
0
    while (seg_allocate_size < requested_size / 2) {
71
0
      seg_allocate_size *= 2;
72
0
    }
73
74
    /* try allocating this much, if not - try shrinking */
75
0
    while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) {
76
0
      first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags);
77
0
      if (first_segment_id != -1) {
78
0
        break;
79
0
      }
80
0
      seg_allocate_size >>= 1; /* shrink the allocated block */
81
0
    }
82
83
0
    if (first_segment_id == -1) {
84
0
      *error_in = "shmget";
85
0
      return ALLOC_FAILURE;
86
0
    }
87
0
  }
88
89
0
  *shared_segments_count = ((requested_size - 1) / seg_allocate_size) + 1;
90
0
  *shared_segments_p = (zend_shared_segment_shm **) calloc(1, (*shared_segments_count) * sizeof(zend_shared_segment_shm) + sizeof(void *) * (*shared_segments_count));
91
0
  if (!*shared_segments_p) {
92
0
    *error_in = "calloc";
93
0
    return ALLOC_FAILURE;
94
0
  }
95
0
  shared_segments = (zend_shared_segment_shm *)((char *)(*shared_segments_p) + sizeof(void *) * (*shared_segments_count));
96
0
  for (i = 0; i < *shared_segments_count; i++) {
97
0
    (*shared_segments_p)[i] = shared_segments + i;
98
0
  }
99
100
0
  remaining_bytes = requested_size;
101
0
  for (i = 0; i < *shared_segments_count; i++) {
102
0
    allocate_size = MIN(remaining_bytes, seg_allocate_size);
103
0
    if (i != 0) {
104
0
      shared_segments[i].shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags);
105
0
    } else {
106
0
      shared_segments[i].shm_id = first_segment_id;
107
0
    }
108
109
0
    if (shared_segments[i].shm_id == -1) {
110
0
      return ALLOC_FAILURE;
111
0
    }
112
113
0
    shared_segments[i].common.p = shmat(shared_segments[i].shm_id, NULL, 0);
114
0
    if (shared_segments[i].common.p == (void *)-1) {
115
0
      *error_in = "shmat";
116
0
      shmctl(shared_segments[i].shm_id, IPC_RMID, &sds);
117
0
      return ALLOC_FAILURE;
118
0
    }
119
0
    shmctl(shared_segments[i].shm_id, IPC_RMID, &sds);
120
121
0
    shared_segments[i].common.pos = 0;
122
0
    shared_segments[i].common.size = allocate_size;
123
0
    remaining_bytes -= allocate_size;
124
0
  }
125
0
  return ALLOC_SUCCESS;
126
0
}
127
128
static int detach_segment(zend_shared_segment_shm *shared_segment)
129
0
{
130
0
  shmdt(shared_segment->common.p);
131
0
  return 0;
132
0
}
133
134
static size_t segment_type_size(void)
135
0
{
136
0
  return sizeof(zend_shared_segment_shm);
137
0
}
138
139
const zend_shared_memory_handlers zend_alloc_shm_handlers = {
140
  (create_segments_t)create_segments,
141
  (detach_segment_t)detach_segment,
142
  segment_type_size
143
};
144
145
#endif /* USE_SHM */