zend_accelerator_util_funcs.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2016 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. | http://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@zend.com> |
  16. | Zeev Suraski <zeev@zend.com> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@zend.com> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include "zend_API.h"
  22. #include "zend_constants.h"
  23. #include "zend_accelerator_util_funcs.h"
  24. #include "zend_persist.h"
  25. #include "zend_shared_alloc.h"
  26. #define ZEND_PROTECTED_REFCOUNT (1<<30)
  27. static zend_uint zend_accel_refcount = ZEND_PROTECTED_REFCOUNT;
  28. #if SIZEOF_SIZE_T <= SIZEOF_LONG
  29. /* If sizeof(void*) == sizeof(ulong) we can use zend_hash index functions */
  30. # define accel_xlat_set(old, new) zend_hash_index_update(&ZCG(bind_hash), (ulong)(zend_uintptr_t)(old), &(new), sizeof(void*), NULL)
  31. # define accel_xlat_get(old, new) zend_hash_index_find(&ZCG(bind_hash), (ulong)(zend_uintptr_t)(old), (void**)&(new))
  32. #else
  33. # define accel_xlat_set(old, new) zend_hash_quick_add(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (ulong)(zend_uintptr_t)(old), (void**)&(new), sizeof(void*), NULL)
  34. # define accel_xlat_get(old, new) zend_hash_quick_find(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (ulong)(zend_uintptr_t)(old), (void**)&(new))
  35. #endif
  36. typedef int (*id_function_t)(void *, void *);
  37. typedef void (*unique_copy_ctor_func_t)(void *pElement);
  38. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  39. static const Bucket *uninitialized_bucket = NULL;
  40. #endif
  41. static int zend_prepare_function_for_execution(zend_op_array *op_array);
  42. static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind);
  43. static void zend_accel_destroy_zend_function(zend_function *function)
  44. {
  45. TSRMLS_FETCH();
  46. if (function->type == ZEND_USER_FUNCTION) {
  47. if (function->op_array.static_variables) {
  48. efree(function->op_array.static_variables);
  49. function->op_array.static_variables = NULL;
  50. }
  51. }
  52. destroy_zend_function(function TSRMLS_CC);
  53. }
  54. static void zend_accel_destroy_zend_class(zend_class_entry **pce)
  55. {
  56. zend_class_entry *ce = *pce;
  57. ce->function_table.pDestructor = (dtor_func_t) zend_accel_destroy_zend_function;
  58. destroy_zend_class(pce);
  59. }
  60. zend_persistent_script* create_persistent_script(void)
  61. {
  62. zend_persistent_script *persistent_script = (zend_persistent_script *) emalloc(sizeof(zend_persistent_script));
  63. memset(persistent_script, 0, sizeof(zend_persistent_script));
  64. zend_hash_init(&persistent_script->function_table, 100, NULL, (dtor_func_t) zend_accel_destroy_zend_function, 0);
  65. /* class_table is usually destroyed by free_persistent_script() that
  66. * overrides destructor. ZEND_CLASS_DTOR may be used by standard
  67. * PHP compiler
  68. */
  69. zend_hash_init(&persistent_script->class_table, 10, NULL, ZEND_CLASS_DTOR, 0);
  70. return persistent_script;
  71. }
  72. static int compact_hash_table(HashTable *ht)
  73. {
  74. uint i = 3;
  75. uint nSize;
  76. Bucket **t;
  77. if (!ht->nNumOfElements) {
  78. /* Empty tables don't allocate space for Buckets */
  79. return 1;
  80. }
  81. if (ht->nNumOfElements >= 0x80000000) {
  82. /* prevent overflow */
  83. nSize = 0x80000000;
  84. } else {
  85. while ((1U << i) < ht->nNumOfElements) {
  86. i++;
  87. }
  88. nSize = 1 << i;
  89. }
  90. if (nSize >= ht->nTableSize) {
  91. /* Keep the size */
  92. return 1;
  93. }
  94. t = (Bucket **)pemalloc(nSize * sizeof(Bucket *), ht->persistent);
  95. if (!t) {
  96. return 0;
  97. }
  98. pefree(ht->arBuckets, ht->persistent);
  99. ht->arBuckets = t;
  100. ht->nTableSize = nSize;
  101. ht->nTableMask = ht->nTableSize - 1;
  102. zend_hash_rehash(ht);
  103. return 1;
  104. }
  105. int compact_persistent_script(zend_persistent_script *persistent_script)
  106. {
  107. return compact_hash_table(&persistent_script->function_table) &&
  108. compact_hash_table(&persistent_script->class_table);
  109. }
  110. void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements)
  111. {
  112. if (destroy_elements) {
  113. persistent_script->function_table.pDestructor = (dtor_func_t)zend_accel_destroy_zend_function;
  114. persistent_script->class_table.pDestructor = (dtor_func_t)zend_accel_destroy_zend_class;
  115. } else {
  116. persistent_script->function_table.pDestructor = NULL;
  117. persistent_script->class_table.pDestructor = NULL;
  118. }
  119. zend_hash_destroy(&persistent_script->function_table);
  120. zend_hash_destroy(&persistent_script->class_table);
  121. if (persistent_script->full_path) {
  122. efree(persistent_script->full_path);
  123. }
  124. efree(persistent_script);
  125. }
  126. static int is_not_internal_function(zend_function *function)
  127. {
  128. return(function->type != ZEND_INTERNAL_FUNCTION);
  129. }
  130. void zend_accel_free_user_functions(HashTable *ht TSRMLS_DC)
  131. {
  132. dtor_func_t orig_dtor = ht->pDestructor;
  133. ht->pDestructor = NULL;
  134. zend_hash_apply(ht, (apply_func_t) is_not_internal_function TSRMLS_CC);
  135. ht->pDestructor = orig_dtor;
  136. }
  137. static int move_user_function(zend_function *function
  138. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  139. TSRMLS_DC
  140. #endif
  141. , int num_args, va_list args, zend_hash_key *hash_key)
  142. {
  143. HashTable *function_table = va_arg(args, HashTable *);
  144. (void)num_args; /* keep the compiler happy */
  145. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  146. TSRMLS_FETCH();
  147. #endif
  148. if (function->type == ZEND_USER_FUNCTION) {
  149. zend_hash_quick_update(function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, function, sizeof(zend_function), NULL);
  150. return 1;
  151. } else {
  152. return 0;
  153. }
  154. }
  155. void zend_accel_move_user_functions(HashTable *src, HashTable *dst TSRMLS_DC)
  156. {
  157. dtor_func_t orig_dtor = src->pDestructor;
  158. src->pDestructor = NULL;
  159. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  160. zend_hash_apply_with_arguments(src, (apply_func_args_t)move_user_function, 1, dst);
  161. #else
  162. zend_hash_apply_with_arguments(src TSRMLS_CC, (apply_func_args_t)move_user_function, 1, dst);
  163. #endif
  164. src->pDestructor = orig_dtor;
  165. }
  166. static int copy_internal_function(zend_function *function, HashTable *function_table TSRMLS_DC)
  167. {
  168. if (function->type == ZEND_INTERNAL_FUNCTION) {
  169. zend_hash_update(function_table, function->common.function_name, strlen(function->common.function_name) + 1, function, sizeof(zend_function), NULL);
  170. }
  171. return 0;
  172. }
  173. void zend_accel_copy_internal_functions(TSRMLS_D)
  174. {
  175. zend_hash_apply_with_argument(CG(function_table), (apply_func_arg_t)copy_internal_function, &ZCG(function_table) TSRMLS_CC);
  176. ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table));
  177. }
  178. static void zend_destroy_property_info(zend_property_info *property_info)
  179. {
  180. interned_efree((char*)property_info->name);
  181. if (property_info->doc_comment) {
  182. efree((char*)property_info->doc_comment);
  183. }
  184. }
  185. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  186. static zend_ast *zend_ast_clone(zend_ast *ast TSRMLS_DC)
  187. {
  188. int i;
  189. zend_ast *node;
  190. if (ast->kind == ZEND_CONST) {
  191. node = emalloc(sizeof(zend_ast) + sizeof(zval));
  192. node->kind = ZEND_CONST;
  193. node->children = 0;
  194. node->u.val = (zval*)(node + 1);
  195. *node->u.val = *ast->u.val;
  196. if ((Z_TYPE_P(ast->u.val) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) {
  197. switch ((Z_TYPE_P(ast->u.val) & IS_CONSTANT_TYPE_MASK)) {
  198. case IS_STRING:
  199. case IS_CONSTANT:
  200. Z_STRVAL_P(node->u.val) = (char *) interned_estrndup(Z_STRVAL_P(ast->u.val), Z_STRLEN_P(ast->u.val));
  201. break;
  202. case IS_ARRAY:
  203. #if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO
  204. case IS_CONSTANT_ARRAY:
  205. #endif
  206. if (ast->u.val->value.ht && ast->u.val->value.ht != &EG(symbol_table)) {
  207. ALLOC_HASHTABLE(node->u.val->value.ht);
  208. zend_hash_clone_zval(node->u.val->value.ht, ast->u.val->value.ht, 0);
  209. }
  210. break;
  211. case IS_CONSTANT_AST:
  212. Z_AST_P(node->u.val) = zend_ast_clone(Z_AST_P(ast->u.val) TSRMLS_CC);
  213. break;
  214. }
  215. }
  216. } else {
  217. node = emalloc(sizeof(zend_ast) + sizeof(zend_ast*) * (ast->children - 1));
  218. node->kind = ast->kind;
  219. node->children = ast->children;
  220. for (i = 0; i < ast->children; i++) {
  221. if ((&ast->u.child)[i]) {
  222. (&node->u.child)[i] = zend_ast_clone((&ast->u.child)[i] TSRMLS_CC);
  223. } else {
  224. (&node->u.child)[i] = NULL;
  225. }
  226. }
  227. }
  228. return node;
  229. }
  230. #endif
  231. static inline zval* zend_clone_zval(zval *src, int bind TSRMLS_DC)
  232. {
  233. zval *ret, **ret_ptr = NULL;
  234. if (!bind) {
  235. ALLOC_ZVAL(ret);
  236. *ret = *src;
  237. INIT_PZVAL(ret);
  238. } else if (Z_REFCOUNT_P(src) == 1) {
  239. ALLOC_ZVAL(ret);
  240. *ret = *src;
  241. } else if (accel_xlat_get(src, ret_ptr) != SUCCESS) {
  242. ALLOC_ZVAL(ret);
  243. *ret = *src;
  244. accel_xlat_set(src, ret);
  245. } else {
  246. return *ret_ptr;
  247. }
  248. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  249. if ((Z_TYPE_P(ret) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) {
  250. switch ((Z_TYPE_P(ret) & IS_CONSTANT_TYPE_MASK)) {
  251. #else
  252. if ((Z_TYPE_P(ret) & ~IS_CONSTANT_INDEX) >= IS_ARRAY) {
  253. switch ((Z_TYPE_P(ret) & ~IS_CONSTANT_INDEX)) {
  254. #endif
  255. case IS_STRING:
  256. case IS_CONSTANT:
  257. Z_STRVAL_P(ret) = (char *) interned_estrndup(Z_STRVAL_P(ret), Z_STRLEN_P(ret));
  258. break;
  259. case IS_ARRAY:
  260. #if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO
  261. case IS_CONSTANT_ARRAY:
  262. #endif
  263. if (ret->value.ht && ret->value.ht != &EG(symbol_table)) {
  264. ALLOC_HASHTABLE(ret->value.ht);
  265. zend_hash_clone_zval(ret->value.ht, src->value.ht, 0);
  266. }
  267. break;
  268. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  269. case IS_CONSTANT_AST:
  270. Z_AST_P(ret) = zend_ast_clone(Z_AST_P(ret) TSRMLS_CC);
  271. break;
  272. #endif
  273. }
  274. }
  275. return ret;
  276. }
  277. static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind)
  278. {
  279. Bucket *p, *q, **prev;
  280. ulong nIndex;
  281. zval *ppz;
  282. TSRMLS_FETCH();
  283. ht->nTableSize = source->nTableSize;
  284. ht->nTableMask = source->nTableMask;
  285. ht->nNumOfElements = source->nNumOfElements;
  286. ht->nNextFreeElement = source->nNextFreeElement;
  287. ht->pDestructor = ZVAL_PTR_DTOR;
  288. #if ZEND_DEBUG
  289. ht->inconsistent = 0;
  290. #endif
  291. ht->persistent = 0;
  292. ht->arBuckets = NULL;
  293. ht->pListHead = NULL;
  294. ht->pListTail = NULL;
  295. ht->pInternalPointer = NULL;
  296. ht->nApplyCount = 0;
  297. ht->bApplyProtection = 1;
  298. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  299. if (!ht->nTableMask) {
  300. ht->arBuckets = (Bucket**)&uninitialized_bucket;
  301. return;
  302. }
  303. #endif
  304. ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
  305. prev = &ht->pListHead;
  306. p = source->pListHead;
  307. while (p) {
  308. nIndex = p->h & ht->nTableMask;
  309. /* Create bucket and initialize key */
  310. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  311. if (!p->nKeyLength) {
  312. q = (Bucket *) emalloc(sizeof(Bucket));
  313. q->arKey = NULL;
  314. } else if (IS_INTERNED(p->arKey)) {
  315. q = (Bucket *) emalloc(sizeof(Bucket));
  316. q->arKey = p->arKey;
  317. } else {
  318. q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
  319. q->arKey = ((char*)q) + sizeof(Bucket);
  320. memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
  321. }
  322. #else
  323. q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
  324. if (p->nKeyLength) {
  325. memcpy(q->arKey, p->arKey, p->nKeyLength);
  326. }
  327. #endif
  328. q->h = p->h;
  329. q->nKeyLength = p->nKeyLength;
  330. /* Insert into hash collision list */
  331. q->pNext = ht->arBuckets[nIndex];
  332. q->pLast = NULL;
  333. if (q->pNext) {
  334. q->pNext->pLast = q;
  335. }
  336. ht->arBuckets[nIndex] = q;
  337. /* Insert into global list */
  338. q->pListLast = ht->pListTail;
  339. ht->pListTail = q;
  340. q->pListNext = NULL;
  341. *prev = q;
  342. prev = &q->pListNext;
  343. /* Copy data */
  344. q->pData = &q->pDataPtr;
  345. if (!bind) {
  346. ALLOC_ZVAL(ppz);
  347. *ppz = *((zval*)p->pDataPtr);
  348. INIT_PZVAL(ppz);
  349. } else if (Z_REFCOUNT_P((zval*)p->pDataPtr) == 1) {
  350. ALLOC_ZVAL(ppz);
  351. *ppz = *((zval*)p->pDataPtr);
  352. } else if (accel_xlat_get(p->pDataPtr, ppz) != SUCCESS) {
  353. ALLOC_ZVAL(ppz);
  354. *ppz = *((zval*)p->pDataPtr);
  355. accel_xlat_set(p->pDataPtr, ppz);
  356. } else {
  357. q->pDataPtr = *(void**)ppz;
  358. p = p->pListNext;
  359. continue;
  360. }
  361. q->pDataPtr = (void*)ppz;
  362. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  363. if ((Z_TYPE_P((zval*)p->pDataPtr) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) {
  364. switch ((Z_TYPE_P((zval*)p->pDataPtr) & IS_CONSTANT_TYPE_MASK)) {
  365. #else
  366. if ((Z_TYPE_P((zval*)p->pDataPtr) & ~IS_CONSTANT_INDEX) >= IS_ARRAY) {
  367. switch ((Z_TYPE_P((zval*)p->pDataPtr) & ~IS_CONSTANT_INDEX)) {
  368. #endif
  369. case IS_STRING:
  370. case IS_CONSTANT:
  371. Z_STRVAL_P(ppz) = (char *) interned_estrndup(Z_STRVAL_P((zval*)p->pDataPtr), Z_STRLEN_P((zval*)p->pDataPtr));
  372. break;
  373. case IS_ARRAY:
  374. #if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO
  375. case IS_CONSTANT_ARRAY:
  376. #endif
  377. if (((zval*)p->pDataPtr)->value.ht && ((zval*)p->pDataPtr)->value.ht != &EG(symbol_table)) {
  378. ALLOC_HASHTABLE(ppz->value.ht);
  379. zend_hash_clone_zval(ppz->value.ht, ((zval*)p->pDataPtr)->value.ht, 0);
  380. }
  381. break;
  382. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  383. case IS_CONSTANT_AST:
  384. Z_AST_P(ppz) = zend_ast_clone(Z_AST_P(ppz) TSRMLS_CC);
  385. break;
  386. #endif
  387. }
  388. }
  389. p = p->pListNext;
  390. }
  391. ht->pInternalPointer = ht->pListHead;
  392. }
  393. static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce TSRMLS_DC)
  394. {
  395. Bucket *p, *q, **prev;
  396. ulong nIndex;
  397. zend_class_entry **new_ce;
  398. zend_function** new_prototype;
  399. zend_op_array *new_entry;
  400. ht->nTableSize = source->nTableSize;
  401. ht->nTableMask = source->nTableMask;
  402. ht->nNumOfElements = source->nNumOfElements;
  403. ht->nNextFreeElement = source->nNextFreeElement;
  404. ht->pDestructor = ZEND_FUNCTION_DTOR;
  405. #if ZEND_DEBUG
  406. ht->inconsistent = 0;
  407. #endif
  408. ht->persistent = 0;
  409. ht->pListHead = NULL;
  410. ht->pListTail = NULL;
  411. ht->pInternalPointer = NULL;
  412. ht->nApplyCount = 0;
  413. ht->bApplyProtection = 1;
  414. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  415. if (!ht->nTableMask) {
  416. ht->arBuckets = (Bucket**)&uninitialized_bucket;
  417. return;
  418. }
  419. #endif
  420. ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
  421. prev = &ht->pListHead;
  422. p = source->pListHead;
  423. while (p) {
  424. nIndex = p->h & ht->nTableMask;
  425. /* Create bucket and initialize key */
  426. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  427. if (!p->nKeyLength) {
  428. q = (Bucket *) emalloc(sizeof(Bucket));
  429. q->arKey = NULL;
  430. } else if (IS_INTERNED(p->arKey)) {
  431. q = (Bucket *) emalloc(sizeof(Bucket));
  432. q->arKey = p->arKey;
  433. } else {
  434. q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
  435. q->arKey = ((char*)q) + sizeof(Bucket);
  436. memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
  437. }
  438. #else
  439. q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
  440. if (p->nKeyLength) {
  441. memcpy(q->arKey, p->arKey, p->nKeyLength);
  442. }
  443. #endif
  444. q->h = p->h;
  445. q->nKeyLength = p->nKeyLength;
  446. /* Insert into hash collision list */
  447. q->pNext = ht->arBuckets[nIndex];
  448. q->pLast = NULL;
  449. if (q->pNext) {
  450. q->pNext->pLast = q;
  451. }
  452. ht->arBuckets[nIndex] = q;
  453. /* Insert into global list */
  454. q->pListLast = ht->pListTail;
  455. ht->pListTail = q;
  456. q->pListNext = NULL;
  457. *prev = q;
  458. prev = &q->pListNext;
  459. /* Copy data */
  460. q->pData = (void *) emalloc(sizeof(zend_function));
  461. new_entry = (zend_op_array*)q->pData;
  462. *new_entry = *(zend_op_array*)p->pData;
  463. q->pDataPtr = NULL;
  464. /* Copy constructor */
  465. /* we use refcount to show that op_array is referenced from several places */
  466. if (new_entry->refcount != NULL) {
  467. accel_xlat_set(p->pData, new_entry);
  468. }
  469. zend_prepare_function_for_execution(new_entry);
  470. if (old_ce == new_entry->scope) {
  471. new_entry->scope = ce;
  472. } else {
  473. if (accel_xlat_get(new_entry->scope, new_ce) == SUCCESS) {
  474. new_entry->scope = *new_ce;
  475. } else {
  476. zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s", ce->name, new_entry->function_name);
  477. }
  478. }
  479. /* update prototype */
  480. if (new_entry->prototype) {
  481. if (accel_xlat_get(new_entry->prototype, new_prototype) == SUCCESS) {
  482. new_entry->prototype = *new_prototype;
  483. } else {
  484. zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s", ce->name, new_entry->function_name);
  485. }
  486. }
  487. p = p->pListNext;
  488. }
  489. ht->pInternalPointer = ht->pListHead;
  490. }
  491. static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce TSRMLS_DC)
  492. {
  493. Bucket *p, *q, **prev;
  494. ulong nIndex;
  495. zend_class_entry **new_ce;
  496. zend_property_info *prop_info;
  497. ht->nTableSize = source->nTableSize;
  498. ht->nTableMask = source->nTableMask;
  499. ht->nNumOfElements = source->nNumOfElements;
  500. ht->nNextFreeElement = source->nNextFreeElement;
  501. ht->pDestructor = (dtor_func_t) zend_destroy_property_info;
  502. #if ZEND_DEBUG
  503. ht->inconsistent = 0;
  504. #endif
  505. ht->persistent = 0;
  506. ht->pListHead = NULL;
  507. ht->pListTail = NULL;
  508. ht->pInternalPointer = NULL;
  509. ht->nApplyCount = 0;
  510. ht->bApplyProtection = 1;
  511. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  512. if (!ht->nTableMask) {
  513. ht->arBuckets = (Bucket**)&uninitialized_bucket;
  514. return;
  515. }
  516. #endif
  517. ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
  518. prev = &ht->pListHead;
  519. p = source->pListHead;
  520. while (p) {
  521. nIndex = p->h & ht->nTableMask;
  522. /* Create bucket and initialize key */
  523. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  524. if (!p->nKeyLength) {
  525. q = (Bucket *) emalloc(sizeof(Bucket));
  526. q->arKey = NULL;
  527. } else if (IS_INTERNED(p->arKey)) {
  528. q = (Bucket *) emalloc(sizeof(Bucket));
  529. q->arKey = p->arKey;
  530. } else {
  531. q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
  532. q->arKey = ((char*)q) + sizeof(Bucket);
  533. memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
  534. }
  535. #else
  536. q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
  537. if (p->nKeyLength) {
  538. memcpy(q->arKey, p->arKey, p->nKeyLength);
  539. }
  540. #endif
  541. q->h = p->h;
  542. q->nKeyLength = p->nKeyLength;
  543. /* Insert into hash collision list */
  544. q->pNext = ht->arBuckets[nIndex];
  545. q->pLast = NULL;
  546. if (q->pNext) {
  547. q->pNext->pLast = q;
  548. }
  549. ht->arBuckets[nIndex] = q;
  550. /* Insert into global list */
  551. q->pListLast = ht->pListTail;
  552. ht->pListTail = q;
  553. q->pListNext = NULL;
  554. *prev = q;
  555. prev = &q->pListNext;
  556. /* Copy data */
  557. q->pData = (void *) emalloc(sizeof(zend_property_info));
  558. prop_info = q->pData;
  559. *prop_info = *(zend_property_info*)p->pData;
  560. q->pDataPtr = NULL;
  561. /* Copy constructor */
  562. prop_info->name = interned_estrndup(prop_info->name, prop_info->name_length);
  563. if (prop_info->doc_comment) {
  564. if (ZCG(accel_directives).load_comments) {
  565. prop_info->doc_comment = estrndup(prop_info->doc_comment, prop_info->doc_comment_len);
  566. } else {
  567. prop_info->doc_comment = NULL;
  568. }
  569. }
  570. if (prop_info->ce == old_ce) {
  571. prop_info->ce = ce;
  572. } else if (accel_xlat_get(prop_info->ce, new_ce) == SUCCESS) {
  573. prop_info->ce = *new_ce;
  574. } else {
  575. zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s, property %s", ce->name, prop_info->name);
  576. }
  577. p = p->pListNext;
  578. }
  579. ht->pInternalPointer = ht->pListHead;
  580. }
  581. /* protects reference count, creates copy of statics */
  582. static int zend_prepare_function_for_execution(zend_op_array *op_array)
  583. {
  584. HashTable *shared_statics = op_array->static_variables;
  585. /* protect reference count */
  586. op_array->refcount = &zend_accel_refcount;
  587. (*op_array->refcount) = ZEND_PROTECTED_REFCOUNT;
  588. /* copy statics */
  589. if (shared_statics) {
  590. ALLOC_HASHTABLE(op_array->static_variables);
  591. zend_hash_clone_zval(op_array->static_variables, shared_statics, 0);
  592. }
  593. return 0;
  594. }
  595. #define zend_update_inherited_handler(handler) \
  596. { \
  597. if (ce->handler != NULL) { \
  598. if (accel_xlat_get(ce->handler, new_func) == SUCCESS) { \
  599. ce->handler = *new_func; \
  600. } else { \
  601. zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s", ce->name); \
  602. } \
  603. } \
  604. }
  605. /* Protects class' refcount, copies default properties, functions and class name */
  606. static void zend_class_copy_ctor(zend_class_entry **pce)
  607. {
  608. zend_class_entry *ce = *pce;
  609. zend_class_entry *old_ce = ce;
  610. zend_class_entry **new_ce;
  611. zend_function **new_func;
  612. TSRMLS_FETCH();
  613. *pce = ce = emalloc(sizeof(zend_class_entry));
  614. *ce = *old_ce;
  615. ce->refcount = 1;
  616. if (old_ce->refcount != 1) {
  617. /* this class is not used as a parent for any other classes */
  618. accel_xlat_set(old_ce, ce);
  619. }
  620. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  621. if (old_ce->default_properties_table) {
  622. int i;
  623. ce->default_properties_table = emalloc(sizeof(zval*) * old_ce->default_properties_count);
  624. for (i = 0; i < old_ce->default_properties_count; i++) {
  625. if (old_ce->default_properties_table[i]) {
  626. ce->default_properties_table[i] = zend_clone_zval(old_ce->default_properties_table[i], 0 TSRMLS_CC);
  627. } else {
  628. ce->default_properties_table[i] = NULL;
  629. }
  630. }
  631. }
  632. #else
  633. zend_hash_clone_zval(&ce->default_properties, &old_ce->default_properties, 0);
  634. #endif
  635. zend_hash_clone_methods(&ce->function_table, &old_ce->function_table, old_ce, ce TSRMLS_CC);
  636. /* static members */
  637. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  638. if (old_ce->default_static_members_table) {
  639. int i;
  640. ce->default_static_members_table = emalloc(sizeof(zval*) * old_ce->default_static_members_count);
  641. for (i = 0; i < old_ce->default_static_members_count; i++) {
  642. if (old_ce->default_static_members_table[i]) {
  643. ce->default_static_members_table[i] = zend_clone_zval(old_ce->default_static_members_table[i], 1 TSRMLS_CC);
  644. } else {
  645. ce->default_static_members_table[i] = NULL;
  646. }
  647. }
  648. }
  649. ce->static_members_table = ce->default_static_members_table;
  650. #else
  651. zend_hash_clone_zval(&ce->default_static_members, &old_ce->default_static_members, 1);
  652. ce->static_members = &ce->default_static_members;
  653. #endif
  654. /* properties_info */
  655. zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce, ce TSRMLS_CC);
  656. /* constants table */
  657. zend_hash_clone_zval(&ce->constants_table, &old_ce->constants_table, 0);
  658. ce->name = interned_estrndup(ce->name, ce->name_length);
  659. /* interfaces aren't really implemented, so we create a new table */
  660. if (ce->num_interfaces) {
  661. ce->interfaces = emalloc(sizeof(zend_class_entry *) * ce->num_interfaces);
  662. memset(ce->interfaces, 0, sizeof(zend_class_entry *) * ce->num_interfaces);
  663. } else {
  664. ce->interfaces = NULL;
  665. }
  666. if (ZEND_CE_DOC_COMMENT(ce)) {
  667. if (ZCG(accel_directives).load_comments) {
  668. ZEND_CE_DOC_COMMENT(ce) = estrndup(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce));
  669. } else {
  670. ZEND_CE_DOC_COMMENT(ce) = NULL;
  671. }
  672. }
  673. if (ce->parent) {
  674. if (accel_xlat_get(ce->parent, new_ce) == SUCCESS) {
  675. ce->parent = *new_ce;
  676. } else {
  677. zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s", ce->name);
  678. }
  679. }
  680. zend_update_inherited_handler(constructor);
  681. zend_update_inherited_handler(destructor);
  682. zend_update_inherited_handler(clone);
  683. zend_update_inherited_handler(__get);
  684. zend_update_inherited_handler(__set);
  685. zend_update_inherited_handler(__call);
  686. /* 5.1 stuff */
  687. zend_update_inherited_handler(serialize_func);
  688. zend_update_inherited_handler(unserialize_func);
  689. zend_update_inherited_handler(__isset);
  690. zend_update_inherited_handler(__unset);
  691. /* 5.2 stuff */
  692. zend_update_inherited_handler(__tostring);
  693. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  694. /* 5.3 stuff */
  695. zend_update_inherited_handler(__callstatic);
  696. #endif
  697. #if ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO
  698. /* 5.6 stuff */
  699. zend_update_inherited_handler(__debugInfo);
  700. #endif
  701. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  702. /* 5.4 traits */
  703. if (ce->trait_aliases) {
  704. zend_trait_alias **trait_aliases;
  705. int i = 0;
  706. while (ce->trait_aliases[i]) {
  707. i++;
  708. }
  709. trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1));
  710. i = 0;
  711. while (ce->trait_aliases[i]) {
  712. trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
  713. memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
  714. trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
  715. memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
  716. if (trait_aliases[i]->trait_method) {
  717. if (trait_aliases[i]->trait_method->method_name) {
  718. trait_aliases[i]->trait_method->method_name =
  719. estrndup(trait_aliases[i]->trait_method->method_name,
  720. trait_aliases[i]->trait_method->mname_len);
  721. }
  722. if (trait_aliases[i]->trait_method->class_name) {
  723. trait_aliases[i]->trait_method->class_name =
  724. estrndup(trait_aliases[i]->trait_method->class_name,
  725. trait_aliases[i]->trait_method->cname_len);
  726. }
  727. }
  728. if (trait_aliases[i]->alias) {
  729. trait_aliases[i]->alias =
  730. estrndup(trait_aliases[i]->alias,
  731. trait_aliases[i]->alias_len);
  732. }
  733. i++;
  734. }
  735. trait_aliases[i] = NULL;
  736. ce->trait_aliases = trait_aliases;
  737. }
  738. if (ce->trait_precedences) {
  739. zend_trait_precedence **trait_precedences;
  740. int i = 0;
  741. while (ce->trait_precedences[i]) {
  742. i++;
  743. }
  744. trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
  745. i = 0;
  746. while (ce->trait_precedences[i]) {
  747. trait_precedences[i] = emalloc(sizeof(zend_trait_precedence));
  748. memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence));
  749. trait_precedences[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
  750. memcpy(trait_precedences[i]->trait_method, ce->trait_precedences[i]->trait_method, sizeof(zend_trait_method_reference));
  751. trait_precedences[i]->trait_method->method_name =
  752. estrndup(trait_precedences[i]->trait_method->method_name,
  753. trait_precedences[i]->trait_method->mname_len);
  754. trait_precedences[i]->trait_method->class_name =
  755. estrndup(trait_precedences[i]->trait_method->class_name,
  756. trait_precedences[i]->trait_method->cname_len);
  757. if (trait_precedences[i]->exclude_from_classes) {
  758. zend_class_entry **exclude_from_classes;
  759. int j = 0;
  760. while (trait_precedences[i]->exclude_from_classes[j]) {
  761. j++;
  762. }
  763. exclude_from_classes = emalloc(sizeof(zend_class_entry*) * (j + 1));
  764. j = 0;
  765. while (trait_precedences[i]->exclude_from_classes[j]) {
  766. exclude_from_classes[j] = (zend_class_entry*)estrndup(
  767. (char*)trait_precedences[i]->exclude_from_classes[j],
  768. strlen((char*)trait_precedences[i]->exclude_from_classes[j]));
  769. j++;
  770. }
  771. exclude_from_classes[j] = NULL;
  772. trait_precedences[i]->exclude_from_classes = exclude_from_classes;
  773. }
  774. i++;
  775. }
  776. trait_precedences[i] = NULL;
  777. ce->trait_precedences = trait_precedences;
  778. }
  779. #endif
  780. }
  781. static int zend_hash_unique_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor, uint size, int ignore_dups, void **fail_data, void **conflict_data)
  782. {
  783. Bucket *p;
  784. void *t;
  785. p = source->pListHead;
  786. while (p) {
  787. if (p->nKeyLength > 0) {
  788. if (zend_hash_quick_add(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t) == SUCCESS) {
  789. if (pCopyConstructor) {
  790. pCopyConstructor(t);
  791. }
  792. } else {
  793. if (p->nKeyLength > 0 && p->arKey[0] == 0) {
  794. /* Mangled key */
  795. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  796. if (zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t) == SUCCESS) {
  797. if (pCopyConstructor) {
  798. pCopyConstructor(t);
  799. }
  800. }
  801. #endif
  802. } else if (!ignore_dups && zend_hash_quick_find(target, p->arKey, p->nKeyLength, p->h, &t) == SUCCESS) {
  803. *fail_data = p->pData;
  804. *conflict_data = t;
  805. return FAILURE;
  806. }
  807. }
  808. } else {
  809. if (!zend_hash_index_exists(target, p->h) && zend_hash_index_update(target, p->h, p->pData, size, &t) == SUCCESS) {
  810. if (pCopyConstructor) {
  811. pCopyConstructor(t);
  812. }
  813. } else if (!ignore_dups && zend_hash_index_find(target,p->h, &t) == SUCCESS) {
  814. *fail_data = p->pData;
  815. *conflict_data = t;
  816. return FAILURE;
  817. }
  818. }
  819. p = p->pListNext;
  820. }
  821. target->pInternalPointer = target->pListHead;
  822. return SUCCESS;
  823. }
  824. static void zend_accel_function_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor)
  825. {
  826. zend_function *function1, *function2;
  827. TSRMLS_FETCH();
  828. if (zend_hash_unique_copy(target, source, pCopyConstructor, sizeof(zend_function), 0, (void**)&function1, (void**)&function2) != SUCCESS) {
  829. CG(in_compilation) = 1;
  830. zend_set_compiled_filename(function1->op_array.filename TSRMLS_CC);
  831. CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
  832. if (function2->type == ZEND_USER_FUNCTION
  833. && function2->op_array.last > 0) {
  834. zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
  835. function1->common.function_name,
  836. function2->op_array.filename,
  837. (int)function2->op_array.opcodes[0].lineno);
  838. } else {
  839. zend_error(E_ERROR, "Cannot redeclare %s()", function1->common.function_name);
  840. }
  841. }
  842. }
  843. static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor TSRMLS_DC)
  844. {
  845. zend_class_entry **pce1, **pce2;
  846. if (zend_hash_unique_copy(target, source, pCopyConstructor, sizeof(zend_class_entry*), ZCG(accel_directives).ignore_dups, (void**)&pce1, (void**)&pce2) != SUCCESS) {
  847. CG(in_compilation) = 1;
  848. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  849. zend_set_compiled_filename((*pce1)->info.user.filename TSRMLS_CC);
  850. CG(zend_lineno) = (*pce1)->info.user.line_start;
  851. #else
  852. zend_set_compiled_filename((*pce1)->filename TSRMLS_CC);
  853. CG(zend_lineno) = (*pce1)->line_start;
  854. #endif
  855. zend_error(E_ERROR, "Cannot redeclare class %s", (*pce1)->name);
  856. }
  857. }
  858. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  859. static void zend_do_delayed_early_binding(zend_op_array *op_array, zend_uint early_binding TSRMLS_DC)
  860. {
  861. zend_uint opline_num = early_binding;
  862. if ((int)opline_num != -1) {
  863. zend_bool orig_in_compilation = CG(in_compilation);
  864. char *orig_compiled_filename = zend_set_compiled_filename(op_array->filename TSRMLS_CC);
  865. zend_class_entry **pce;
  866. CG(in_compilation) = 1;
  867. while ((int)opline_num != -1) {
  868. if (zend_lookup_class(Z_STRVAL(op_array->opcodes[opline_num - 1].op2.u.constant), Z_STRLEN(op_array->opcodes[opline_num - 1].op2.u.constant), &pce TSRMLS_CC) == SUCCESS) {
  869. do_bind_inherited_class(&op_array->opcodes[opline_num], EG(class_table), *pce, 1 TSRMLS_CC);
  870. }
  871. opline_num = op_array->opcodes[opline_num].result.u.opline_num;
  872. }
  873. zend_restore_compiled_filename(orig_compiled_filename TSRMLS_CC);
  874. CG(in_compilation) = orig_in_compilation;
  875. }
  876. }
  877. #endif
  878. zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory TSRMLS_DC)
  879. {
  880. zend_op_array *op_array;
  881. op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
  882. *op_array = persistent_script->main_op_array;
  883. if (from_shared_memory) {
  884. /* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
  885. if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
  886. zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0);
  887. zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, (unique_copy_ctor_func_t) zend_class_copy_ctor TSRMLS_CC);
  888. zend_hash_destroy(&ZCG(bind_hash));
  889. }
  890. /* we must first to copy all classes and then prepare functions, since functions may try to bind
  891. classes - which depend on pre-bind class entries existent in the class table */
  892. if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
  893. zend_accel_function_hash_copy(CG(function_table), &persistent_script->function_table, (unique_copy_ctor_func_t)zend_prepare_function_for_execution);
  894. }
  895. zend_prepare_function_for_execution(op_array);
  896. /* Register __COMPILER_HALT_OFFSET__ constant */
  897. if (persistent_script->compiler_halt_offset != 0 &&
  898. persistent_script->full_path) {
  899. char *name, *cfilename;
  900. char haltoff[] = "__COMPILER_HALT_OFFSET__";
  901. int len, clen;
  902. cfilename = persistent_script->full_path;
  903. clen = strlen(cfilename);
  904. zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, cfilename, clen, 0);
  905. if (!zend_hash_exists(EG(zend_constants), name, len + 1)) {
  906. zend_register_long_constant(name, len + 1, persistent_script->compiler_halt_offset, CONST_CS, 0 TSRMLS_CC);
  907. }
  908. efree(name);
  909. }
  910. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  911. if ((int)persistent_script->early_binding != -1) {
  912. zend_do_delayed_early_binding(op_array, persistent_script->early_binding TSRMLS_CC);
  913. }
  914. #endif
  915. } else /* if (!from_shared_memory) */ {
  916. if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
  917. zend_accel_function_hash_copy(CG(function_table), &persistent_script->function_table, NULL);
  918. }
  919. if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
  920. zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, NULL TSRMLS_CC);
  921. }
  922. }
  923. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  924. if (op_array->early_binding != (zend_uint)-1) {
  925. char *orig_compiled_filename = CG(compiled_filename);
  926. CG(compiled_filename) = persistent_script->full_path;
  927. zend_do_delayed_early_binding(op_array TSRMLS_CC);
  928. CG(compiled_filename) = orig_compiled_filename;
  929. }
  930. #endif
  931. if (!from_shared_memory) {
  932. free_persistent_script(persistent_script, 0); /* free only hashes */
  933. }
  934. return op_array;
  935. }
  936. /*
  937. * zend_adler32() is based on zlib implementation
  938. * Computes the Adler-32 checksum of a data stream
  939. *
  940. * Copyright (C) 1995-2005 Mark Adler
  941. * For conditions of distribution and use, see copyright notice in zlib.h
  942. *
  943. * Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
  944. *
  945. * This software is provided 'as-is', without any express or implied
  946. * warranty. In no event will the authors be held liable for any damages
  947. * arising from the use of this software.
  948. *
  949. * Permission is granted to anyone to use this software for any purpose,
  950. * including commercial applications, and to alter it and redistribute it
  951. * freely, subject to the following restrictions:
  952. *
  953. * 1. The origin of this software must not be misrepresented; you must not
  954. * claim that you wrote the original software. If you use this software
  955. * in a product, an acknowledgment in the product documentation would be
  956. * appreciated but is not required.
  957. * 2. Altered source versions must be plainly marked as such, and must not be
  958. * misrepresented as being the original software.
  959. * 3. This notice may not be removed or altered from any source distribution.
  960. *
  961. */
  962. #define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
  963. #define ADLER32_NMAX 5552
  964. /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
  965. #define ADLER32_DO1(buf) {s1 += *(buf); s2 += s1;}
  966. #define ADLER32_DO2(buf, i) ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1);
  967. #define ADLER32_DO4(buf, i) ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2);
  968. #define ADLER32_DO8(buf, i) ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4);
  969. #define ADLER32_DO16(buf) ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8);
  970. unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len)
  971. {
  972. unsigned int s1 = checksum & 0xffff;
  973. unsigned int s2 = (checksum >> 16) & 0xffff;
  974. signed char *end;
  975. while (len >= ADLER32_NMAX) {
  976. len -= ADLER32_NMAX;
  977. end = buf + ADLER32_NMAX;
  978. do {
  979. ADLER32_DO16(buf);
  980. buf += 16;
  981. } while (buf != end);
  982. s1 %= ADLER32_BASE;
  983. s2 %= ADLER32_BASE;
  984. }
  985. if (len) {
  986. if (len >= 16) {
  987. end = buf + (len & 0xfff0);
  988. len &= 0xf;
  989. do {
  990. ADLER32_DO16(buf);
  991. buf += 16;
  992. } while (buf != end);
  993. }
  994. if (len) {
  995. end = buf + len;
  996. do {
  997. ADLER32_DO1(buf);
  998. buf++;
  999. } while (buf != end);
  1000. }
  1001. s1 %= ADLER32_BASE;
  1002. s2 %= ADLER32_BASE;
  1003. }
  1004. return (s2 << 16) | s1;
  1005. }