xref: /PHP-5.4/Zend/zend_string.c (revision c0d060f5)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2014 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 #endif
65 
66 	zend_new_interned_string = zend_new_interned_string_int;
67 	zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
68 	zend_interned_strings_restore = zend_interned_strings_restore_int;
69 }
70 
zend_interned_strings_dtor(TSRMLS_D)71 void zend_interned_strings_dtor(TSRMLS_D)
72 {
73 #ifndef ZTS
74 #if ZEND_DEBUG_INTERNED_STRINGS
75 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
76 #endif
77 	free(CG(interned_strings).arBuckets);
78 	free(CG(interned_strings_start));
79 #endif
80 }
81 
zend_new_interned_string_int(const char * arKey,int nKeyLength,int free_src TSRMLS_DC)82 static const char *zend_new_interned_string_int(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
83 {
84 #ifndef ZTS
85 	ulong h;
86 	uint nIndex;
87 	Bucket *p;
88 
89 	if (IS_INTERNED(arKey)) {
90 		return arKey;
91 	}
92 
93 	h = zend_inline_hash_func(arKey, nKeyLength);
94 	nIndex = h & CG(interned_strings).nTableMask;
95 	p = CG(interned_strings).arBuckets[nIndex];
96 	while (p != NULL) {
97 		if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
98 			if (!memcmp(p->arKey, arKey, nKeyLength)) {
99 				if (free_src) {
100 					efree((void *)arKey);
101 				}
102 				return p->arKey;
103 			}
104 		}
105 		p = p->pNext;
106 	}
107 
108 	if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
109 	    CG(interned_strings_end)) {
110 	    /* no memory */
111 		return arKey;
112 	}
113 
114 	p = (Bucket *) CG(interned_strings_top);
115 	CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
116 
117 #if ZEND_DEBUG_INTERNED_STRINGS
118 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE);
119 #endif
120 
121 	p->arKey = (char*)(p+1);
122 	memcpy((char*)p->arKey, arKey, nKeyLength);
123 	if (free_src) {
124 		efree((void *)arKey);
125 	}
126 	p->nKeyLength = nKeyLength;
127 	p->h = h;
128 	p->pData = &p->pDataPtr;
129 	p->pDataPtr = p;
130 
131 	p->pNext = CG(interned_strings).arBuckets[nIndex];
132 	p->pLast = NULL;
133 	if (p->pNext) {
134 		p->pNext->pLast = p;
135 	}
136 
137 	HANDLE_BLOCK_INTERRUPTIONS();
138 
139 	p->pListLast = CG(interned_strings).pListTail;
140 	CG(interned_strings).pListTail = p;
141 	p->pListNext = NULL;
142 	if (p->pListLast != NULL) {
143 		p->pListLast->pListNext = p;
144 	}
145 	if (!CG(interned_strings).pListHead) {
146 		CG(interned_strings).pListHead = p;
147 	}
148 
149 	CG(interned_strings).arBuckets[nIndex] = p;
150 
151 	HANDLE_UNBLOCK_INTERRUPTIONS();
152 
153 	CG(interned_strings).nNumOfElements++;
154 
155 	if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) {
156 		if ((CG(interned_strings).nTableSize << 1) > 0) {	/* Let's double the table size */
157 			Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent);
158 
159 			if (t) {
160 				HANDLE_BLOCK_INTERRUPTIONS();
161 				CG(interned_strings).arBuckets = t;
162 				CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1);
163 				CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
164 				zend_hash_rehash(&CG(interned_strings));
165 				HANDLE_UNBLOCK_INTERRUPTIONS();
166 			}
167 		}
168 	}
169 
170 #if ZEND_DEBUG_INTERNED_STRINGS
171 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
172 #endif
173 
174 	return p->arKey;
175 #else
176 	return arKey;
177 #endif
178 }
179 
zend_interned_strings_snapshot_int(TSRMLS_D)180 static void zend_interned_strings_snapshot_int(TSRMLS_D)
181 {
182 	CG(interned_strings_snapshot_top) = CG(interned_strings_top);
183 }
184 
zend_interned_strings_restore_int(TSRMLS_D)185 static void zend_interned_strings_restore_int(TSRMLS_D)
186 {
187 #ifndef ZTS
188 	Bucket *p;
189 	int i;
190 #endif
191 
192 	CG(interned_strings_top) = CG(interned_strings_snapshot_top);
193 
194 #ifndef ZTS
195 #if ZEND_DEBUG_INTERNED_STRINGS
196 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ);
197 #endif
198 
199 	for (i = 0; i < CG(interned_strings).nTableSize; i++) {
200 		p = CG(interned_strings).arBuckets[i];
201 		while (p && p->arKey > CG(interned_strings_top)) {
202 			CG(interned_strings).nNumOfElements--;
203 			if (p->pListLast != NULL) {
204 				p->pListLast->pListNext = p->pListNext;
205 			} else {
206 				CG(interned_strings).pListHead = p->pListNext;
207 			}
208 			if (p->pListNext != NULL) {
209 				p->pListNext->pListLast = p->pListLast;
210 			} else {
211 				CG(interned_strings).pListTail = p->pListLast;
212 			}
213 			p = p->pNext;
214 		}
215 		if (p) {
216 			p->pLast = NULL;
217 		}
218 		CG(interned_strings).arBuckets[i] = p;
219 	}
220 
221 #if ZEND_DEBUG_INTERNED_STRINGS
222 	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
223 #endif
224 #endif
225 }
226 
227 /*
228  * Local variables:
229  * tab-width: 4
230  * c-basic-offset: 4
231  * indent-tabs-mode: t
232  * End:
233  */
234