root/eaccelerator/tags/0.9.5-beta2/ea_restore.c

Revision 195, 31.0 kB (checked in by hans, 3 years ago)

Fixed handling of interfaces. This fixes sf.net bug #1440575

  • Property svn:eol-style set to native
  • Property svn:keywords set to svn:eol-style
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | eAccelerator project                                                 |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2004 - 2006 eAccelerator                               |
6    | http://eaccelerator.net                                              |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    $Id: ea_restore.c 176 2006-03-05 12:18:54Z bart $
26 */
27
28 #include "eaccelerator.h"
29
30 #ifdef HAVE_EACCELERATOR
31
32 #include "debug.h"
33 #include "ea_restore.h"
34 #include "opcodes.h"
35 #include "zend.h"
36 #include "zend_API.h"
37 #include "zend_extensions.h"
38 #ifdef ZEND_ENGINE_2_1
39 #include "zend_vm.h"
40 #endif
41
42 #ifndef INCOMPLETE_CLASS
43 #  define INCOMPLETE_CLASS "__PHP_Incomplete_Class"
44 #endif
45 #ifndef MAGIC_MEMBER
46 #  define MAGIC_MEMBER "__PHP_Incomplete_Class_Name"
47 #endif
48
49 extern zend_extension *ZendOptimizer;
50 #if HARDENING_PATCH_HASH_PROTECT
51 extern unsigned int zend_hash_canary;
52 #endif
53
54 #ifdef ZEND_ENGINE_2
55 /* pointer to the properties_info hashtable destructor */
56 dtor_func_t properties_info_dtor = NULL;
57
58 /* This function creates a dummy class entry to steal the pointer to the
59  * properties_info hashtable destructor because it's declared static */
60 dtor_func_t get_zend_destroy_property_info(TSRMLS_D)
61 {
62         dtor_func_t property_dtor;
63         zend_class_entry dummy_class_entry;
64         dummy_class_entry.type = ZEND_USER_CLASS;
65
66         zend_initialize_class_data(&dummy_class_entry, 1 TSRMLS_CC);
67
68         property_dtor = dummy_class_entry.properties_info.pDestructor;
69
70         zend_hash_destroy(&dummy_class_entry.default_properties);
71         zend_hash_destroy(&dummy_class_entry.function_table);
72         zend_hash_destroy(&dummy_class_entry.constants_table);
73         zend_hash_destroy(&dummy_class_entry.properties_info);
74 #  ifdef ZEND_ENGINE_2_1
75         zend_hash_destroy(&dummy_class_entry.default_static_members);
76 #  endif
77 #  if defined(ZEND_ENGINE_2) && !defined(ZEND_ENGINE_2_1)
78         zend_hash_destroy(dummy_class_entry.static_members);
79         FREE_HASHTABLE(dummy_class_entry.static_members);
80 #  endif
81         return property_dtor;
82 }
83 #endif
84
85 /******************************************************************************/
86 /* Functions to restore a cached script from file cache                       */
87 /******************************************************************************/
88
89 typedef void (*fixup_bucket_t) (void *TSRMLS_DC);
90
91 #define fixup_zval_hash(from) \
92     fixup_hash(from, (fixup_bucket_t)fixup_zval TSRMLS_CC)
93
94 #ifdef ZEND_ENGINE_2
95 static void fixup_property_info(zend_property_info * from TSRMLS_DC)
96 {
97         FIXUP(from->name);
98 #ifdef ZEND_ENGINE_2_1
99         FIXUP(from->doc_comment);
100 #endif
101 }
102 #endif
103
104 static void fixup_hash(HashTable * source,
105                                            fixup_bucket_t fixup_bucket TSRMLS_DC)
106 {
107         unsigned int i;
108         Bucket *p;
109
110         if (source->nNumOfElements > 0) {
111                 if (!EAG(compress)) {
112                         if (source->arBuckets != NULL) {
113                                 FIXUP(source->arBuckets);
114                                 for (i = 0; i < source->nTableSize; i++) {
115                                         FIXUP(source->arBuckets[i]);
116                                 }
117                         }
118                 }
119                 FIXUP(source->pListHead);
120                 FIXUP(source->pListTail);
121
122                 p = source->pListHead;
123                 while (p) {
124                         FIXUP(p->pNext);
125                         FIXUP(p->pLast);
126                         FIXUP(p->pData);
127                         FIXUP(p->pDataPtr);
128                         FIXUP(p->pListLast);
129                         FIXUP(p->pListNext);
130                         if (p->pDataPtr) {
131                                 fixup_bucket(p->pDataPtr TSRMLS_CC);
132                                 p->pData = &p->pDataPtr;
133                         } else {
134                                 fixup_bucket(p->pData TSRMLS_CC);
135                         }
136                         p = p->pListNext;
137                 }
138                 source->pInternalPointer = source->pListHead;
139         }
140 }
141
142 void fixup_zval(zval * zv TSRMLS_DC)
143 {
144         switch (zv->type & ~IS_CONSTANT_INDEX) {
145         case IS_CONSTANT:                       /* fallthrough */
146         case IS_STRING:
147                 if (zv->value.str.val == NULL || zv->value.str.len == 0) {
148                         zv->value.str.val = empty_string;
149                         zv->value.str.len = 0;
150                 } else {
151                         FIXUP(zv->value.str.val);
152                 }
153                 break;
154         case IS_ARRAY:                          /* fallthrough */
155         case IS_CONSTANT_ARRAY:
156                 if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
157                 } else {
158                         FIXUP(zv->value.ht);
159                         fixup_zval_hash(zv->value.ht);
160                 }
161                 break;
162         case IS_OBJECT:
163                 if (!EAG(compress)) {
164                         return;
165                 }
166 #ifndef ZEND_ENGINE_2
167                 FIXUP(zv->value.obj.ce);
168                 if (zv->value.obj.properties != NULL) {
169                         FIXUP(zv->value.obj.properties);
170                         fixup_zval_hash(zv->value.obj.properties);
171                 }
172 #endif
173         default:
174                 break;
175         }
176 }
177
178 void fixup_op_array(eaccelerator_op_array * from TSRMLS_DC)
179 {
180         zend_op *opline;
181         zend_op *end;
182
183 #ifdef ZEND_ENGINE_2
184         if (from->num_args > 0) {
185                 zend_uint i;
186                 FIXUP(from->arg_info);
187                 for (i = 0; i < from->num_args; i++) {
188                         FIXUP(from->arg_info[i].name);
189                         FIXUP(from->arg_info[i].class_name);
190                 }
191         }
192 #else
193         FIXUP(from->arg_types);
194 #endif
195         FIXUP(from->function_name);
196 #ifdef ZEND_ENGINE_2
197         FIXUP(from->scope_name);
198 #endif
199         if (from->type == ZEND_INTERNAL_FUNCTION) {
200                 return;
201         }
202
203         if (from->opcodes != NULL) {
204                 FIXUP(from->opcodes);
205
206                 opline = from->opcodes;
207                 end = opline + from->last;
208                 EAG(compress) = 0;
209                 for (; opline < end; opline++) {
210                         /*
211                            if (opline->result.op_type == IS_CONST)
212                            fixup_zval(&opline->result.u.constant TSRMLS_CC);
213                          */
214                         if (opline->op1.op_type == IS_CONST)
215                                 fixup_zval(&opline->op1.u.constant TSRMLS_CC);
216                         if (opline->op2.op_type == IS_CONST)
217                                 fixup_zval(&opline->op2.u.constant TSRMLS_CC);
218 #ifdef ZEND_ENGINE_2
219                         switch (opline->opcode) {
220                         case ZEND_JMP:
221                                 FIXUP(opline->op1.u.jmp_addr);
222                                 break;
223                         case ZEND_JMPZ: /* fallthrough */
224                         case ZEND_JMPNZ:
225                         case ZEND_JMPZ_EX:
226                         case ZEND_JMPNZ_EX:
227                                 FIXUP(opline->op2.u.jmp_addr);
228                                 break;
229                         }
230 #  ifdef ZEND_ENGINE_2_1
231                         ZEND_VM_SET_OPCODE_HANDLER(opline);
232 #  else
233                         opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
234 #  endif
235
236 #endif
237                 }
238                 EAG(compress) = 1;
239         }
240         FIXUP(from->brk_cont_array);
241 #ifdef ZEND_ENGINE_2
242         FIXUP(from->try_catch_array);
243 #endif
244         if (from->static_variables != NULL) {
245                 FIXUP(from->static_variables);
246                 fixup_zval_hash(from->static_variables);
247         }
248 #ifdef ZEND_ENGINE_2_1
249         if (from->vars != NULL) {
250                 int i;
251                 FIXUP(from->vars);
252                 for (i = 0; i < from->last_var; i++) {
253                         FIXUP(from->vars[i].name);
254                 }
255         }
256 #endif
257         FIXUP(from->filename);
258 #ifdef ZEND_ENGINE_2
259         FIXUP(from->doc_comment);
260 #endif
261 }
262
263 void fixup_class_entry(eaccelerator_class_entry * from TSRMLS_DC)
264 {
265         FIXUP(from->name);
266         FIXUP(from->parent);
267 #ifdef ZEND_ENGINE_2
268         FIXUP(from->filename);
269         FIXUP(from->doc_comment);
270         fixup_zval_hash(&from->constants_table);
271         fixup_zval_hash(&from->default_properties);
272         fixup_hash(&from->properties_info,
273                            (fixup_bucket_t) fixup_property_info TSRMLS_CC);
274 #  ifdef ZEND_ENGINE_2_1
275         fixup_zval_hash(&from->default_static_members);
276         if (from->static_members != NULL) {
277                 FIXUP(from->static_members);
278                 if (from->static_members != &from->default_static_members) {
279                         fixup_zval_hash(from->static_members);
280                 }
281         }
282 #  else
283         if (from->static_members != NULL) {
284                 FIXUP(from->static_members);
285                 fixup_zval_hash(from->static_members);
286         }
287 #  endif
288 #else
289         fixup_zval_hash(&from->default_properties);
290 #endif
291         fixup_hash(&from->function_table,
292                            (fixup_bucket_t) fixup_op_array TSRMLS_CC);
293 }
294
295 /******************************************************************************/
296 /* Functions to restore a php script from shared memory                       */
297 /******************************************************************************/
298
299 typedef void *(*restore_bucket_t) (void *TSRMLS_DC);
300
301 #define restore_zval_hash(target, source) \
302     restore_hash(target, source, (restore_bucket_t)restore_zval_ptr TSRMLS_CC)
303
304 static zval *restore_zval_ptr(zval * from TSRMLS_DC)
305 {
306         zval *p;
307         ALLOC_ZVAL(p);
308         memcpy(p, from, sizeof(zval));
309         restore_zval(p TSRMLS_CC);
310         /* hrak: reset refcount to make sure there is one reference to this val, and prevent memleaks */
311         p->refcount = 1;
312         return p;
313 }
314
315 static HashTable *restore_hash(HashTable * target, HashTable * source,
316                                                            restore_bucket_t copy_bucket TSRMLS_DC)
317 {
318         Bucket *p, *np, *prev_p;
319         int nIndex;
320
321         if (target == NULL) {
322                 ALLOC_HASHTABLE(target);
323         }
324         memcpy(target, source, sizeof(HashTable));
325         target->arBuckets =
326                 (Bucket **) emalloc(target->nTableSize * sizeof(Bucket *));
327         memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket *));
328         target->pDestructor = NULL;
329         target->persistent = 0;
330         target->pListHead = NULL;
331         target->pListTail = NULL;
332 #if HARDENING_PATCH_HASH_PROTECT
333     target->canary = zend_hash_canary;
334 #endif
335
336         p = source->pListHead;
337         prev_p = NULL;
338         np = NULL;
339         while (p) {
340                 np = (Bucket *) emalloc(offsetof(Bucket, arKey) + p->nKeyLength);
341                 /*    np = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength); */
342                 nIndex = p->h % source->nTableSize;
343                 if (target->arBuckets[nIndex]) {
344                         np->pNext = target->arBuckets[nIndex];
345                         np->pLast = NULL;
346                         np->pNext->pLast = np;
347                 } else {
348                         np->pNext = NULL;
349                         np->pLast = NULL;
350                 }
351                 target->arBuckets[nIndex] = np;
352                 np->h = p->h;
353                 np->nKeyLength = p->nKeyLength;
354
355                 if (p->pDataPtr == NULL) {
356                         np->pData = copy_bucket(p->pData TSRMLS_CC);
357                         np->pDataPtr = NULL;
358                 } else {
359                         np->pDataPtr = copy_bucket(p->pDataPtr TSRMLS_CC);
360                         np->pData = &np->pDataPtr;
361                 }
362                 np->pListLast = prev_p;
363                 np->pListNext = NULL;
364
365                 memcpy(np->arKey, p->arKey, p->nKeyLength);
366
367                 if (prev_p) {
368                         prev_p->pListNext = np;
369                 } else {
370                         target->pListHead = np;
371                 }
372                 prev_p = np;
373                 p = p->pListNext;
374         }
375         target->pListTail = np;
376         target->pInternalPointer = target->pListHead;
377         return target;
378 }
379
380 void restore_zval(zval * zv TSRMLS_DC)
381 {
382         switch (zv->type & ~IS_CONSTANT_INDEX) {
383         case IS_CONSTANT:
384         case IS_STRING:
385                 if (zv->value.str.val == NULL || zv->value.str.val == "" || zv->value.str.len == 0) {
386             zv->value.str.len = 0;
387                         zv->value.str.val = empty_string;
388                         return;
389                 } else {
390                         char *p = emalloc(zv->value.str.len + 1);
391                         memcpy(p, zv->value.str.val, zv->value.str.len + 1);
392                         zv->value.str.val = p;
393                 }
394                 return;
395
396         case IS_ARRAY:
397         case IS_CONSTANT_ARRAY:
398                 if (zv->value.ht != NULL && zv->value.ht != &EG(symbol_table)) {
399                         zv->value.ht = restore_zval_hash(NULL, zv->value.ht);
400                         zv->value.ht->pDestructor = ZVAL_PTR_DTOR;
401                 }
402                 return;
403
404         case IS_OBJECT:
405     {
406 #ifndef ZEND_ENGINE_2
407         zend_bool incomplete_class = 0;
408         char *class_name = (char *) zv->value.obj.ce;
409         int name_len = 0;
410         if (!EAG(compress)) {
411             return;
412         }
413         if (class_name != NULL) {
414             zend_class_entry *ce = NULL;
415             name_len = strlen(class_name);
416             if (zend_hash_find(CG(class_table), (void *) class_name, name_len + 1, (void **) &ce) != SUCCESS) {
417                 char *lowercase_name = estrndup(INCOMPLETE_CLASS, sizeof(INCOMPLETE_CLASS));
418                 zend_str_tolower(lowercase_name, sizeof(INCOMPLETE_CLASS));
419                 if (zend_hash_find(CG(class_table), lowercase_name, sizeof(INCOMPLETE_CLASS), (void **) &ce) != SUCCESS) {
420                     efree(lowercase_name);
421                     zend_error(E_ERROR, "EACCELERATOR can't restore object's class \"%s\"", class_name);
422                 } else {
423                     efree(lowercase_name);
424                     zv->value.obj.ce = ce;
425                     incomplete_class = 1;
426                 }
427             } else {
428                 zv->value.obj.ce = ce;
429             }
430         }
431         if (zv->value.obj.properties != NULL) {
432             zv->value.obj.properties = restore_zval_hash(NULL, zv->value.obj.properties);
433             zv->value.obj.properties->pDestructor = ZVAL_PTR_DTOR;
434             /* Clearing references */
435             {
436                 Bucket *p = zv->value.obj.properties->pListHead;
437                 while (p != NULL) {
438                     ((zval *) (p->pDataPtr))->refcount = 1;
439                     p = p->pListNext;
440                 }
441             }
442         }
443         if (incomplete_class && class_name != NULL) {
444             zval *val;
445             MAKE_STD_ZVAL(val);
446             Z_TYPE_P(val) = IS_STRING;
447             Z_STRVAL_P(val) = estrndup(class_name, name_len);
448             Z_STRLEN_P(val) = name_len;
449             zend_hash_update(Z_OBJPROP_P(zv), MAGIC_MEMBER, sizeof(MAGIC_MEMBER), &val, sizeof(val), NULL);
450         }
451 #endif
452         return;
453     }
454         }
455 }
456
457 static void call_op_array_ctor_handler(zend_extension * extension,
458                                                                            zend_op_array * op_array TSRMLS_DC)
459 {
460         if (extension->op_array_ctor) {
461                 extension->op_array_ctor(op_array);
462         }
463 }
464
465 zend_op_array *restore_op_array(zend_op_array * to,
466                                                                 eaccelerator_op_array * from TSRMLS_DC)
467 {
468         zend_function *function;
469 #ifdef ZEND_ENGINE_2
470         int fname_len = 0;
471         char *fname_lc = NULL;
472 #endif
473
474         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
475         DBG(ea_debug_printf, (EA_DEBUG, "[%d] restore_op_array: %s type=%x\n", getpid(),
476                                         from->function_name ? from->function_name : "(top)", from->type));
477
478         if (from->type == ZEND_INTERNAL_FUNCTION) {
479                 if (to == NULL) {
480                         to = emalloc(sizeof(zend_internal_function));
481                 }
482                 memset(to, 0, sizeof(zend_internal_function));
483         } else {
484                 if (to == NULL) {
485                         to = emalloc(sizeof(zend_op_array));
486                 }
487                 memset(to, 0, sizeof(zend_op_array));
488                 if (ZendOptimizer) {
489                         zend_llist_apply_with_argument(&zend_extensions,
490                     (llist_apply_with_arg_func_t) call_op_array_ctor_handler, to TSRMLS_CC);
491                 }
492         }
493         to->type = from->type;
494 #ifdef ZEND_ENGINE_2
495         to->num_args = from->num_args;
496         to->required_num_args = from->required_num_args;
497         to->arg_info = from->arg_info;
498         to->pass_rest_by_reference = from->pass_rest_by_reference;
499 #else
500         to->arg_types = from->arg_types;
501 #endif
502         to->function_name = from->function_name;
503
504 #ifdef ZEND_ENGINE_2
505         if (to->function_name) {
506                 fname_len = strlen(to->function_name);
507                 fname_lc = zend_str_tolower_dup(to->function_name, fname_len);
508         }
509
510         to->fn_flags = from->fn_flags;
511
512         /* segv74:
513          * to->scope = EAG(class_entry)
514          *
515          * if  from->scope_name == NULL,
516          *     ; EAG(class) == NULL  : we are in function or outside function.
517          *     ; EAG(class) != NULL  : inherited method not defined in current file, should have to find.
518          *                              just LINK (zend_op_array *) to to original entry in parent,
519          *                              but, with what? !!! I don't know PARENT CLASS NAME !!!!
520          *
521          *
522          * if  from->scope_name != NULL,
523          *     ; we are in class member function
524          *
525          *     ; we have to find appropriate (zend_class_entry*) to->scope for name from->scope_name
526          *     ; if we find in CG(class_table), link to it.
527          *     ; if fail, it should be EAG(class_entry)
528          *   
529          * am I right here ? ;-(
530          */
531         if (from->scope_name != NULL) {
532                 char *from_scope_lc = zend_str_tolower_dup(from->scope_name, from->scope_name_len);
533                 if (zend_hash_find (CG(class_table), (void *) from_scope_lc, from->scope_name_len + 1, (void **) &to->scope) != SUCCESS) {
534                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
535                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   can't find '%s' in class_table. use EAG(class_entry).\n", getpid(), from->scope_name));
536                         to->scope = EAG(class_entry);
537                 } else {
538                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
539                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   found '%s' in hash\n", getpid(), from->scope_name));
540                         to->scope = *(zend_class_entry **) to->scope;
541                 }
542                 efree(from_scope_lc);
543         } else {                                        // zoeloelip: is this needed? scope is always stored -> hra: no its not :P only if from->scope!=null in ea_store
544                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
545                 DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   from is NULL\n", getpid()));
546                 if (EAG(class_entry)) {
547                         zend_class_entry *p;
548                         for (p = EAG(class_entry)->parent; p; p = p->parent) {
549                                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
550                                 DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   checking parent '%s' have '%s'\n", getpid(), p->name, fname_lc));
551                                 if (zend_hash_find(&p->function_table, fname_lc, fname_len + 1, (void **) &function) == SUCCESS) {
552                                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
553                                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                   '%s' has '%s' of scope '%s'\n",
554                             getpid(), p->name, fname_lc, function->common.scope->name));
555                                         to->scope = function->common.scope;
556                                         break;
557                                 }
558                         }
559                 } else {
560                         to->scope = NULL;
561                 }
562         }
563
564         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
565         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   %s's scope is '%s'\n", getpid(),
566             from->function_name ? from->function_name : "(top)", to->scope ? to->scope->name : "NULL"));
567 #endif
568         if (from->type == ZEND_INTERNAL_FUNCTION) {
569                 zend_class_entry *class_entry = EAG(class_entry);
570                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
571                 DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   [internal function from=%08x,to=%08x] class_entry='%s' [%08x]\n",
572                 getpid(), from, to, class_entry->name, class_entry));
573                 if (class_entry) {
574                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
575                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                       class_entry->parent='%s' [%08x]\n",
576                     getpid(), class_entry->parent->name, class_entry->parent));
577                 }
578                 if (class_entry != NULL && class_entry->parent != NULL &&
579                 zend_hash_find(&class_entry->parent->function_table,
580 #ifdef ZEND_ENGINE_2
581                 fname_lc, fname_len + 1,
582 #else
583                 to->function_name, strlen(to->function_name) + 1,
584 #endif
585                                 (void **) &function) == SUCCESS && function->type == ZEND_INTERNAL_FUNCTION) {
586                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
587                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                       found in function table\n", getpid()));
588                         ((zend_internal_function *) (to))->handler = ((zend_internal_function *) function)->handler;
589                 } else {
590                         /* FIXME. I don't know how to fix handler.
591                          * TODO: must solve this somehow, to avoid returning damaged structure...
592                          */
593                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
594                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                       can't find\n", getpid()));
595                 }               
596 #ifdef ZEND_ENGINE_2
597                 /* hrak: slight memleak here. dont forget to free the lowercase function name! */
598                 if (fname_lc != NULL) {
599                         efree(fname_lc);
600                 }
601                 /* zend_internal_function also contains return_reference in ZE2 */
602                 to->return_reference = from->return_reference;
603                 /* this gets set by zend_do_inheritance */
604                 to->prototype = NULL;
605 #endif
606                 return to;
607         }
608 #ifdef ZEND_ENGINE_2
609         /* hrak: slight memleak here. dont forget to free the lowercase function name! */
610         if (fname_lc != NULL) {
611                 efree(fname_lc);
612         }
613 #endif
614         to->opcodes = from->opcodes;
615         to->last = to->size = from->last;
616         to->T = from->T;
617         to->brk_cont_array = from->brk_cont_array;
618         to->last_brk_cont = from->last_brk_cont;
619        
620            to->current_brk_cont = -1;
621            to->static_variables = from->static_variables;
622 /*         to->start_op         = to->opcodes; */
623            to->backpatch_count  = 0;
624        
625         to->return_reference = from->return_reference;
626         to->done_pass_two = 1;
627         to->filename = from->filename;
628 /*      if (from->filename != NULL) {
629                 size_t len = strlen(from->filename) + 1;
630                 to->filename = emalloc(len);
631                 memcpy(to->filename, from->filename, len);
632         }*/
633
634 #ifdef ZEND_ENGINE_2
635         /* HOESH: try & catch support */
636         to->try_catch_array = from->try_catch_array;
637         to->last_try_catch = from->last_try_catch;
638         to->uses_this = from->uses_this;
639
640         to->line_start = from->line_start;
641         to->line_end = from->line_end;
642         to->doc_comment_len = from->doc_comment_len;
643         to->doc_comment = from->doc_comment;
644         /*???
645            if (from->doc_comment != NULL) {
646            to->doc_comment = emalloc(from->doc_comment_len+1);
647            memcpy(to->doc_comment, from->doc_comment, from->doc_comment_len+1);
648            }
649          */
650 #else
651         to->uses_globals = from->uses_globals;
652 #endif
653         if (from->static_variables) {
654                 to->static_variables = restore_zval_hash(NULL, from->static_variables);
655                 to->static_variables->pDestructor = ZVAL_PTR_DTOR;
656 #ifndef ZEND_ENGINE_2
657                 if (EAG(class_entry) != NULL) {
658                         Bucket *p = to->static_variables->pListHead;
659                         while (p != NULL) {
660                                 ((zval *) (p->pDataPtr))->refcount = 1;
661                                 p = p->pListNext;
662                         }
663                 }
664 #endif
665         }
666
667 #ifdef ZEND_ENGINE_2_1
668         to->vars             = from->vars;
669         to->last_var         = from->last_var;
670         to->size_var         = 0;
671 /*      if (from->vars) {
672                 zend_uint i;
673                 to->vars = (zend_compiled_variable*)emalloc(from->last_var*sizeof(zend_compiled_variable));             
674                 memcpy(to->vars, from->vars, sizeof(zend_compiled_variable) * from->last_var);
675                 for (i = 0; i < from->last_var; i ++) {
676                         to->vars[i].name = estrndup(from->vars[i].name, from->vars[i].name_len);
677                 }
678         }*/
679 #endif
680
681         /* disable deletion in destroy_op_array */
682         ++EAG(refcount_helper);
683         to->refcount = &EAG(refcount_helper);
684
685         return to;
686 }
687
688 static zend_op_array *restore_op_array_ptr(eaccelerator_op_array *
689                                                                                    from TSRMLS_DC)
690 {
691         return restore_op_array(NULL, from TSRMLS_CC);
692 }
693
694 #ifdef ZEND_ENGINE_2
695 static zend_property_info *restore_property_info(zend_property_info *
696                                                                                                  from TSRMLS_DC)
697 {
698         zend_property_info *to = emalloc(sizeof(zend_property_info));
699         memcpy(to, from, sizeof(zend_property_info));
700         to->name = emalloc(from->name_length + 1);
701         memcpy(to->name, from->name, from->name_length + 1);
702 #ifdef ZEND_ENGINE_2_1
703         if (from->doc_comment != NULL) {
704                 to->doc_comment = emalloc(from->doc_comment_len+1);
705                 memcpy(to->doc_comment, from->doc_comment, from->doc_comment_len+1);
706         }
707 #endif
708         return to;
709 }
710 #endif
711
712 /* restore the parent class with the given name for the given class */
713 void restore_class_parent(char *parent, int len,
714                                                   zend_class_entry * to TSRMLS_DC)
715 {
716 #ifdef ZEND_ENGINE_2
717         zend_class_entry** parent_ptr = NULL;
718         if (zend_lookup_class(parent, len, &parent_ptr TSRMLS_CC) != SUCCESS)
719 #else
720         char *name_lc = estrndup(parent, len);
721         zend_str_tolower(name_lc, len);
722         if (zend_hash_find(CG(class_table), (void *) name_lc, len + 1, (void **) &to->parent) != SUCCESS)
723 #endif
724         {
725                 DBG(ea_debug_error, ("[%d] EACCELERATOR can't restore parent class \"%s\" of class \"%s\"\n",
726                 getpid(), (char *) parent, to->name));
727                 to->parent = NULL;
728         } else {
729                 /* parent found */
730 #ifdef ZEND_ENGINE_2
731                 to->parent = *parent_ptr;
732                 to->constructor = to->parent->constructor;
733                 to->destructor = to->parent->destructor;
734                 to->clone = to->parent->clone;
735 #endif
736                 DBG(ea_debug_printf, (EA_DEBUG, "restore_class_parent: found parent %s..\n", to->parent->name));
737                 DBG(ea_debug_printf, (EA_DEBUG, "restore_class_parent: parent type=%d child type=%d\n", to->parent->type, to->type));
738         }
739 #ifndef ZEND_ENGINE_2
740         efree(name_lc);
741 #endif
742 }
743
744 #ifdef ZEND_ENGINE_2
745 void restore_class_methods(zend_class_entry * to TSRMLS_DC)
746 {
747         int cname_len = to->name_length;
748         char *cname_lc = zend_str_tolower_dup(to->name, cname_len);
749         int fname_len = 0;
750         char *fname_lc = NULL;
751         zend_function *f = NULL;
752         zend_function *old_ctor = to->constructor;
753         Bucket *p = to->function_table.pListHead;
754
755         while (p != NULL) {
756                 f = p->pData;
757                 fname_len = strlen(f->common.function_name);
758                 fname_lc = zend_str_tolower_dup(f->common.function_name, fname_len);
759
760                 if (fname_len == cname_len && !memcmp(fname_lc, cname_lc, fname_len) &&
761                 to->constructor == old_ctor && f->common.scope != to->parent) {
762                         to->constructor = f;
763                 } else if (fname_lc[0] == '_' && fname_lc[1] == '_' && f->common.scope != to->parent) {
764                         if (fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME) - 1 &&
765                     memcmp(fname_lc, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
766                                 to->constructor = f;
767                         else if (fname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 &&
768                                          memcmp(fname_lc, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
769                                 to->destructor = f;
770                         else if (fname_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 &&
771                                          memcmp(fname_lc, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
772                                 to->clone = f;
773                         else if (fname_len == sizeof(ZEND_GET_FUNC_NAME) - 1 &&
774                                          memcmp(fname_lc, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
775                                 to->__get = f;
776                         else if (fname_len == sizeof(ZEND_SET_FUNC_NAME) - 1 &&
777                                          memcmp(fname_lc, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
778                                 to->__set = f;
779 #  ifdef ZEND_ENGINE_2_1
780                         else if (fname_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 &&
781                                         memcmp(fname_lc, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)) == 0)
782                                 to->__unset = f;
783                         else if (fname_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 &&
784                                         memcmp(fname_lc, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)) == 0)
785                                 to->__isset = f;
786 #  endif
787                         else if (fname_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 &&
788                                          memcmp(fname_lc, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
789                                 to->__call = f;
790                 }
791                 if (to->parent) {
792                         /* clear the child's prototype and IMPLEMENTED_ABSTRACT flag,
793                            these are properly restored by zend_do_inheritance() (see do_inherit_method_check) */
794                         f->common.prototype = NULL;
795                         f->common.fn_flags = f->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
796                 }
797                 efree(fname_lc);
798                 p = p->pListNext;
799         }
800         efree(cname_lc);
801 }
802 #endif
803
804 zend_class_entry *restore_class_entry(zend_class_entry * to,
805                                                                           eaccelerator_class_entry * from TSRMLS_DC)
806 {
807         zend_class_entry *old;
808         zend_function *f = NULL;
809
810         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
811         DBG(ea_debug_printf, (EA_DEBUG, "[%d] restore_class_entry: %s\n", getpid(), from->name ? from->name : "(top)"));
812 #ifdef DEBUG
813         EAG(xpad)++;
814 #endif
815         if (to == NULL) {
816                 to = emalloc(sizeof(zend_class_entry));
817         }
818         memset(to, 0, sizeof(zend_class_entry));
819         to->type = from->type;
820         /*
821            to->name        = NULL;
822            to->name_length = from->name_length;
823            to->constants_updated = 0;
824            to->parent      = NULL;
825          */
826 #ifdef ZEND_ENGINE_2
827         to->ce_flags = from->ce_flags;
828         to->num_interfaces = from->num_interfaces;
829         to->interfaces = NULL;
830
831         if (to->num_interfaces > 0) {
832                 /* hrak: Allocate the slots which will later be populated by ZEND_ADD_INTERFACE */
833                 to->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *) * to->num_interfaces);
834                 memset(to->interfaces, 0, sizeof(zend_class_entry *) * to->num_interfaces);
835         }
836 #endif
837
838         if (from->name != NULL) {
839                 to->name_length = from->name_length;
840                 to->name = emalloc(from->name_length + 1);
841                 memcpy(to->name, from->name, from->name_length + 1);
842         }
843
844         old = EAG(class_entry);
845         EAG(class_entry) = to;
846
847 #ifdef ZEND_ENGINE_2
848         to->refcount = 1;
849
850         to->line_start = from->line_start;
851         to->line_end = from->line_end;
852         to->doc_comment_len = from->doc_comment_len;
853 /*      if (from->filename != NULL) {
854                 size_t len = strlen(from->filename) + 1;
855                 to->filename = emalloc(len);
856                 memcpy(to->filename, from->filename, len);
857         }*/
858         to->filename = from->filename;
859         if (from->doc_comment != NULL) {
860                 to->doc_comment = emalloc(from->doc_comment_len + 1);
861                 memcpy(to->doc_comment, from->doc_comment, from->doc_comment_len + 1);
862         }
863
864         /* restore constants table */
865         restore_zval_hash(&to->constants_table, &from->constants_table);
866         to->constants_table.pDestructor = ZVAL_PTR_DTOR;
867         /* restore default properties */
868         restore_zval_hash(&to->default_properties, &from->default_properties);
869         to->default_properties.pDestructor = ZVAL_PTR_DTOR;
870         /* restore properties */
871         restore_hash(&to->properties_info, &from->properties_info,
872             (restore_bucket_t) restore_property_info TSRMLS_CC);
873         to->properties_info.pDestructor = properties_info_dtor;
874
875 #  ifdef ZEND_ENGINE_2_1
876         /* restore default_static_members */
877         restore_zval_hash(&to->default_static_members, &from->default_static_members);
878         to->default_static_members.pDestructor = ZVAL_PTR_DTOR;
879        
880         if (from->static_members != &(from->default_static_members)) {
881                 ALLOC_HASHTABLE(to->static_members);
882                 restore_zval_hash(to->static_members, from->static_members);
883                 to->static_members->pDestructor = ZVAL_PTR_DTOR;
884         } else {
885                 to->static_members = &(to->default_static_members);
886         }
887 #  else
888         if (from->static_members != NULL) {
889                 ALLOC_HASHTABLE(to->static_members);
890                 restore_zval_hash(to->static_members, from->static_members);
891                 to->static_members->pDestructor = ZVAL_PTR_DTOR;
892         }
893 #  endif
894 #else
895         to->refcount = emalloc(sizeof(*to->refcount));
896         *to->refcount = 1;
897
898         restore_zval_hash(&to->default_properties, &from->default_properties);
899         to->default_properties.pDestructor = ZVAL_PTR_DTOR;
900         /* Clearing references */
901         {
902                 Bucket *p = to->default_properties.pListHead;
903                 while (p != NULL) {
904                         ((zval *) (p->pDataPtr))->refcount = 1;
905                         p = p->pListNext;
906                 }
907         }
908 #endif
909         if (from->parent != NULL) {
910                 restore_class_parent(from->parent, strlen(from->parent), to TSRMLS_CC);
911         } else {
912                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
913                 DBG(ea_debug_printf, (EA_DEBUG, "[%d] parent = NULL\n", getpid()));
914                 to->parent = NULL;
915         }
916
917         restore_hash(&to->function_table, &from->function_table,
918                                  (restore_bucket_t) restore_op_array_ptr TSRMLS_CC);
919         to->function_table.pDestructor = ZEND_FUNCTION_DTOR;
920
921 #ifdef ZEND_ENGINE_2
922         restore_class_methods(to TSRMLS_CC);
923 #endif
924         if (to->parent)
925                 zend_do_inheritance(to, to->parent TSRMLS_CC);
926         EAG(class_entry) = old;
927
928 #ifdef DEBUG
929         EAG(xpad)--;
930 #endif
931
932         return to;
933 }
934
935 void restore_function(mm_fc_entry * p TSRMLS_DC)
936 {