root/eaccelerator/tags/0.9.5/ea_restore.c

Revision 271, 31.4 kB (checked in by bart, 2 years ago)

Only put the function that has the same name as the class as contructor

if there isn't a construct function. This fixes ticket #172

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