source: trunk/mmap.c @ 119

Last change on this file since 119 was 119, checked in by moo, 8 years ago

fix leak in xcache.test=1; XCACHE_VERSION/XCACHE_MODULES length off-by-one

File size: 5.7 KB
RevLine 
[1]1
2#undef ALLOC_DEBUG
3
4#include <stdio.h>
5#include <assert.h>
6#include <limits.h>
7#include <string.h>
8#include <stdlib.h>
[11]9
[1]10/* mmap */
[11]11#ifdef ZEND_WIN32
12#   define ftruncate chsize
13#   define getuid() 0
[83]14#   include <process.h>
[57]15#   define XCacheCreateFileMapping(size, perm, name) \
[11]16        CreateFileMapping(INVALID_HANDLE_VALUE, NULL, perm, (sizeof(xc_shmsize_t) > 4) ? size >> 32 : 0, size & 0xffffffff, name)
17#   define XCACHE_MAP_FAILED NULL
18#   define munmap(p, s) UnmapViewOfFile(p)
19#else
20#   include <unistd.h>
[79]21/* make sure to mark(change) it to NULL to keep consistent */
[11]22#   define XCACHE_MAP_FAILED MAP_FAILED
23#endif
24
[1]25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
[11]28
29#ifndef ZEND_WIN32
[1]30#include <sys/mman.h>
[11]31#endif
[1]32
33#include "php.h"
34#include "myshm.h"
35
36#ifndef max
37#define max(a, b) ((a) < (b) ? (b) : (a))
38#endif
39
40// {{{ xc_shm_t
41struct _xc_shm_t {
42    void *ptr;
43    void *ptr_ro;
44    long  diff;
45    xc_shmsize_t size;
[11]46    char *name;
[57]47    int newfile;
[11]48#ifdef ZEND_WIN32
49    HANDLE hmap;
50    HANDLE hmap_ro;
51#endif
[1]52};
53
[11]54#undef NDEBUG
[1]55#ifdef ALLOC_DEBUG
56#   define inline
57#else
58#   define NDEBUG
59#endif
60#include <assert.h>
61/* }}} */
62#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
[11]63#define PTR_ADD(ptr, v) (((char *) (ptr)) + (v))
64#define PTR_SUB(ptr, v) (((char *) (ptr)) - (v))
[1]65
66int xc_shm_can_readonly(xc_shm_t *shm) /* {{{ */
67{
68    return shm->ptr_ro != NULL;
69}
70/* }}} */
71int xc_shm_is_readwrite(xc_shm_t *shm, const void *p) /* {{{ */
72{
73    return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
74}
75/* }}} */
76int xc_shm_is_readonly(xc_shm_t *shm, const void *p) /* {{{ */
77{
78    return xc_shm_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
79}
80/* }}} */
81void *xc_shm_to_readwrite(xc_shm_t *shm, void *p) /* {{{ */
82{
83    if (shm->diff) {
84        assert(xc_shm_is_readonly(p));
[59]85        p = PTR_SUB(p, shm->diff);
[1]86    }
87    assert(xc_shm_is_readwrite(p));
88    return p;
89}
90/* }}} */
91void *xc_shm_to_readonly(xc_shm_t *shm, void *p) /* {{{ */
92{
93    assert(xc_shm_is_readwrite(p));
94    if (shm->diff) {
[11]95        p = PTR_ADD(p, shm->diff);
[1]96        assert(xc_shm_is_readonly(p));
97    }
98    return p;
99}
100/* }}} */
101
102void xc_shm_destroy(xc_shm_t *shm) /* {{{ */
103{
104    if (shm->ptr_ro) {
105        munmap(shm->ptr_ro, shm->size);
106        /*
107        shm->ptr_ro = NULL;
108        */
109    }
110    if (shm->ptr) {
111        /* shm->size depends on shm->ptr */
112        munmap(shm->ptr, shm->size);
113        /*
114        shm->ptr = NULL;
115        */
116    }
[11]117#ifdef ZEND_WIN32
118    if (shm->hmap) {
119        CloseHandle(shm->hmap);
120    }
121    if (shm->hmap_ro) {
122        CloseHandle(shm->hmap_ro);
123    }
124#endif
125
126    if (shm->name) {
127#ifdef __CYGWIN__
[57]128        if (shm->newfile) {
129            unlink(shm->name);
130        }
[11]131#endif
132        free(shm->name);
133    }
[1]134    /*
135    shm->size = NULL;
136    shm->diff = 0;
137    */
138
139    free(shm);
140    return;
141}
142/* }}} */
143xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_protection) /* {{{ */
144{
[21]145#ifdef ZEND_WIN32
146#   define TMP_PATH "XCache"
147#else
148#   define TMP_PATH "/tmp/XCache"
149#endif
[1]150    xc_shm_t *shm = NULL;
[11]151    int fd = -1;
[1]152    int ro_ok;
153    volatile void *romem;
[21]154    char tmpname[sizeof(TMP_PATH) - 1 + 100];
[119]155    const char *errstr = NULL;
[1]156
157    CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
158    shm->size = size;
[11]159
[1]160    if (path == NULL || !path[0]) {
[11]161        static int inc = 0;
[83]162        snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", TMP_PATH, (int) getuid(), (int) getpid(), inc ++, rand());
[11]163        path = tmpname;
[1]164    }
[83]165#ifdef ZEND_WIN32
166    else {
167        static int inc2 = 0;
168        snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", path, (int) getuid(), (int) getpid(), inc2 ++, rand());
169        path = tmpname;
170    }
171#endif
[11]172
173    shm->name = strdup(path);
174
175#ifndef ZEND_WIN32
176#   define XCACHE_MMAP_PERMISSION (S_IRUSR | S_IWUSR)
177    fd = open(shm->name, O_RDWR, XCACHE_MMAP_PERMISSION);
[1]178    if (fd == -1) {
[61]179        /* do not create file in /dev */
180        if (strncmp(shm->name, "/dev", 4) == 0) {
[119]181            perror(shm->name);
182            errstr = "Cannot open file set by xcache.mmap_path";
[61]183            goto err;
184        }
[11]185        fd = open(shm->name, O_CREAT | O_RDWR, XCACHE_MMAP_PERMISSION);
[57]186        shm->newfile = 1;
[1]187        if (fd == -1) {
[119]188            perror(shm->name);
189            errstr = "Cannot open or create file set by xcache.mmap_path";
[1]190            goto err;
191        }
192    }
193    ftruncate(fd, size);
[11]194#endif
[1]195
[11]196#ifdef ZEND_WIN32
[57]197    shm->hmap = XCacheCreateFileMapping(size, PAGE_READWRITE, shm->name);
[11]198    shm->ptr = (LPSTR) MapViewOfFile(shm->hmap, FILE_MAP_WRITE, 0, 0, 0);
199#else
[1]200    shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
[11]201#endif
202
203    if (shm->ptr == XCACHE_MAP_FAILED) {
[119]204        perror(shm->name);
205        errstr = "Failed creating file mappping";
[1]206        shm->ptr = NULL;
207        goto err;
208    }
209
[79]210    /* {{{ readonly protection, mmap it readonly and check if ptr_ro works */
[1]211    if (readonly_protection) {
[79]212        ro_ok = 0;
213
[11]214#ifdef ZEND_WIN32
[57]215        shm->hmap_ro = XCacheCreateFileMapping(size, PAGE_READONLY, shm->name);
[11]216        shm->ptr_ro = (LPSTR) MapViewOfFile(shm->hmap_ro, FILE_MAP_READ, 0, 0, 0);
217#else
[1]218        shm->ptr_ro = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
[11]219#endif
[79]220        if (shm->ptr_ro == XCACHE_MAP_FAILED) {
221            shm->ptr_ro = NULL;
222        }
[1]223        romem = shm->ptr_ro;
224
225        do {
[79]226            if (romem == NULL || romem == shm->ptr) {
[1]227                break;
228            }
229            *(char *)shm->ptr = 1;
230            if (*(char *)romem != 1) {
231                break;
232            }
233            *(char *)shm->ptr = 2;
234            if (*(char *)romem != 2) {
235                break;
236            }
237            ro_ok = 1;
238        } while (0);
239
[79]240        if (ro_ok) {
241            shm->diff = PTR_SUB(shm->ptr_ro, (char *) shm->ptr);
242            /* no overlap */
243            assert(abs(shm->diff) >= size);
[1]244        }
[79]245        else {
246            if (shm->ptr_ro) {
247                munmap(shm->ptr_ro, size);
248            }
249#ifdef ZEND_WIN32
250            if (shm->hmap_ro) {
251                CloseHandle(shm->hmap_ro);
252            }
253#endif
254            shm->ptr_ro = NULL;
255            shm->diff = 0;
256        }
[1]257    }
[79]258
[1]259    /* }}} */
260
261    close(fd);
[11]262#ifndef __CYGWIN__
[57]263    if (shm->newfile) {
264        unlink(shm->name);
265    }
[11]266#endif
[1]267
268    return shm;
269
270err:
[11]271    if (fd != -1) {
272        close(fd);
273    }
[1]274    if (shm) {
275        xc_shm_destroy(shm);
276    }
[119]277    if (errstr) {
278        fprintf(stderr, "%s\n", errstr);
279        zend_error(E_ERROR, "%s", errstr);
280    }
[1]281    return NULL;
282}
283/* }}} */
284
285void *xc_shm_ptr(xc_shm_t *shm) /* {{{ */
286{
287    return shm->ptr;
288}
289/* }}} */
Note: See TracBrowser for help on using the repository browser.