root/eaccelerator/trunk/ea_restore.c

Revision 352, 29.6 kB (checked in by bart, 1 month ago)

optimize.c: In php 5.3 this field is const
ea_restore.c: strings comparison can't be done like that, stupid me

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