root/eaccelerator/branches/new-cache/ea_restore.c

Revision 331, 32.7 kB (checked in by bart, 1 year ago)

Rewrite the fixup_* functions they no longer use the EAG(mem) global

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