xref: /PHP-5.6/Zend/zend_string.c (revision 3537e95d)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend 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    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
16    +----------------------------------------------------------------------+
17 */
18 
19 /* $Id: $ */
20 
21 #include "zend.h"
22 #include "zend_globals.h"
23 
24 #ifndef ZEND_DEBUG_INTERNED_STRINGS
25 # define ZEND_DEBUG_INTERNED_STRINGS 0
26 #endif
27 
28 #if ZEND_DEBUG_INTERNED_STRINGS
29 # include <sys/mman.h>
30 #endif
31 
32 ZEND_API const char *(*zend_new_interned_string)(const char *str, int len, int free_src TSRMLS_DC);
33 ZEND_API void (*zend_interned_strings_snapshot)(TSRMLS_D);
34 ZEND_API void (*zend_interned_strings_restore)(TSRMLS_D);
35 
36 static const char *zend_new_interned_string_int(const char *str, int len, int free_src TSRMLS_DC);
37 static void zend_interned_strings_snapshot_int(TSRMLS_D);
38 static void zend_interned_strings_restore_int(TSRMLS_D);
39 
zend_interned_strings_init(TSRMLS_D)40 void zend_interned_strings_init(TSRMLS_D)
41 {
42 #ifndef ZTS
43 	size_t size = 1024 * 1024;
44 
45 #if ZEND_DEBUG_INTERNED_STRINGS
46 	CG(interned_strings_start) = valloc(size);
47 #else
48 	CG(interned_strings_start) = malloc(size);
49 #endif
50 
51 	CG(interned_strings_top) = CG(interned_strings_start);
52 	CG(interned_strings_snapshot_top) = CG(interned_strings_start);
53 	CG(interned_strings_end) = CG(interned_strings_start) + size;
54 
55 	zend_hash_init(&CG(interned_strings), 0, NULL, NULL, 1);
56 
57 	CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
58 	CG(interned_strings).arBuckets = (Bucket **) pecalloc(CG(interned_strings).nTableSize, sizeof(Bucket *), CG(interned_strings).persistent);
59 
60 #if ZEND_DEBUG_INTERNED_STRINGS
61 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
62 #endif
63 
64     /* interned empty string */
65 	CG(interned_empty_string) = zend_new_interned_string_int("", sizeof(""), 0 TSRMLS_CC);
66 #endif
67 
68 	zend_new_interned_string = zend_new_interned_string_int;
69 	zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
70 	zend_interned_strings_restore = zend_interned_strings_restore_int;
71 }
72 
zend_interned_strings_dtor(TSRMLS_D)73 void zend_interned_strings_dtor(TSRMLS_D)
74 {
75 #ifndef ZTS
76 #if ZEND_DEBUG_INTERNED_STRINGS
77 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
78 #endif
79 	free(CG(interned_strings).arBuckets);
80 	free(CG(interned_strings_start));
81 #endif
82 }
83 
zend_new_interned_string_int(const char * arKey,int nKeyLength,int free_src TSRMLS_DC)84 static const char *zend_new_interned_string_int(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
85 {
86 #ifndef ZTS
87 	ulong h;
88 	uint nIndex;
89 	Bucket *p;
90 
91 	if (IS_INTERNED(arKey)) {
92 		return arKey;
93 	}
94 
95 	h = zend_inline_hash_func(arKey, nKeyLength);
96 	nIndex = h & CG(interned_strings).nTableMask;
97 	p = CG(interned_strings).arBuckets[nIndex];
98 	while (p != NULL) {
99 		if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
100 			if (!memcmp(p->arKey, arKey, nKeyLength)) {
101 				if (free_src) {
102 					efree((void *)arKey);
103 				}
104 				return p->arKey;
105 			}
106 		}
107 		p = p->pNext;
108 	}
109 
110 	if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
111 	    CG(interned_strings_end)) {
112 	    /* no memory */
113 		return arKey;
114 	}
115 
116 	p = (Bucket *) CG(interned_strings_top);
117 	CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
118 
119 #if ZEND_DEBUG_INTERNED_STRINGS
120 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE);
121 #endif
122 
123 	p->arKey = (char*)(p+1);
124 	memcpy((char*)p->arKey, arKey, nKeyLength);
125 	if (free_src) {
126 		efree((void *)arKey);
127 	}
128 	p->nKeyLength = nKeyLength;
129 	p->h = h;
130 	p->pData = &p->pDataPtr;
131 	p->pDataPtr = p;
132 
133 	p->pNext = CG(interned_strings).arBuckets[nIndex];
134 	p->pLast = NULL;
135 	if (p->pNext) {
136 		p->pNext->pLast = p;
137 	}
138 
139 	HANDLE_BLOCK_INTERRUPTIONS();
140 
141 	p->pListLast = CG(interned_strings).pListTail;
142 	CG(interned_strings).pListTail = p;
143 	p->pListNext = NULL;
144 	if (p->pListLast != NULL) {
145 		p->pListLast->pListNext = p;
146 	}
147 	if (!CG(interned_strings).pListHead) {
148 		CG(interned_strings).pListHead = p;
149 	}
150 
151 	CG(interned_strings).arBuckets[nIndex] = p;
152 
153 	HANDLE_UNBLOCK_INTERRUPTIONS();
154 
155 	CG(interned_strings).nNumOfElements++;
156 
157 	if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) {
158 		if ((CG(interned_strings).nTableSize << 1) > 0) {	/* Let's double the table size */
159 			Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent);
160 
161 			if (t) {
162 				HANDLE_BLOCK_INTERRUPTIONS();
163 				CG(interned_strings).arBuckets = t;
164 				CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1);
165 				CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
166 				zend_hash_rehash(&CG(interned_strings));
167 				HANDLE_UNBLOCK_INTERRUPTIONS();
168 			}
169 		}
170 	}
171 
172 #if ZEND_DEBUG_INTERNED_STRINGS
173 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
174 #endif
175 
176 	return p->arKey;
177 #else
178 	return arKey;
179 #endif
180 }
181 
zend_interned_strings_snapshot_int(TSRMLS_D)182 static void zend_interned_strings_snapshot_int(TSRMLS_D)
183 {
184 	CG(interned_strings_snapshot_top) = CG(interned_strings_top);
185 }
186 
zend_interned_strings_restore_int(TSRMLS_D)187 static void zend_interned_strings_restore_int(TSRMLS_D)
188 {
189 #ifndef ZTS
190 	Bucket *p;
191 	int i;
192 #endif
193 
194 	CG(interned_strings_top) = CG(interned_strings_snapshot_top);
195 
196 #ifndef ZTS
197 #if ZEND_DEBUG_INTERNED_STRINGS
198 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
199 #endif
200 
201 	for (i = 0; i < CG(interned_strings).nTableSize; i++) {
202 		p = CG(interned_strings).arBuckets[i];
203 		while (p && p->arKey > CG(interned_strings_top)) {
204 			CG(interned_strings).nNumOfElements--;
205 			if (p->pListLast != NULL) {
206 				p->pListLast->pListNext = p->pListNext;
207 			} else {
208 				CG(interned_strings).pListHead = p->pListNext;
209 			}
210 			if (p->pListNext != NULL) {
211 				p->pListNext->pListLast = p->pListLast;
212 			} else {
213 				CG(interned_strings).pListTail = p->pListLast;
214 			}
215 			p = p->pNext;
216 		}
217 		if (p) {
218 			p->pLast = NULL;
219 		}
220 		CG(interned_strings).arBuckets[i] = p;
221 	}
222 
223 #if ZEND_DEBUG_INTERNED_STRINGS
224 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
225 #endif
226 #endif
227 }
228 
229 /*
230  * Local variables:
231  * tab-width: 4
232  * c-basic-offset: 4
233  * indent-tabs-mode: t
234  * End:
235  */
236