root/eaccelerator/tags/0.9.3-rc2/loader.c

Revision 95, 37.1 kB (checked in by zoeloelip, 3 years ago)

Fix for must constructor related problems with encoded scripts and php5. Also a fixes
memory leak in the loader. (Thanks larnot)

  • 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 - 2005 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    | Author(s): Dmitry Stogov <dstogov@users.sourceforge.net>             |
26    +----------------------------------------------------------------------+
27    $Id$
28 */
29
30 #include "eaccelerator.h"
31 #include "eaccelerator_version.h"
32
33 #ifdef HAVE_EACCELERATOR
34 #ifdef WITH_EACCELERATOR_LOADER
35
36 #include "opcodes.h"
37 #include "zend.h"
38 #include "zend_API.h"
39 #include "php.h"
40 #include <math.h>
41
42 typedef struct loader_data {
43   long  version;
44   char* filename;
45   uint  lineno;
46 } loader_data;
47
48 static inline unsigned char decode(char** p, unsigned int* l) {
49   unsigned char c;
50   if (*l == 0) {
51     zend_bailout();
52   }
53   c = **p;
54   (*p)++;
55   (*l)--;
56   return c;
57 }
58
59 static inline unsigned int decode32(char** p, unsigned int* l) {
60   unsigned int i = decode(p, l);
61   i += ((unsigned int)decode(p, l)) << 8;
62   i += ((unsigned int)decode(p, l)) << 16;
63   i += ((unsigned int)decode(p, l)) << 24;
64   return i;
65 }
66
67 static inline unsigned short decode16(char** p, unsigned int* l) {
68   unsigned short i = decode(p, l);
69   i += ((unsigned short)decode(p, l)) << 8;
70   return i;
71 }
72
73 static unsigned int decode_var(unsigned int count, char** p, unsigned int* l) {
74   unsigned int var;
75   if (count < 0xff) {
76     var = decode(p, l);
77   } else if (count < 0xffff) {
78     var = decode16(p, l);
79   } else {
80     var = decode32(p, l);
81   }
82   if (var >= count) {
83     zend_bailout();
84   }
85 #ifdef ZEND_ENGINE_2
86   return (unsigned int)(((temp_variable*)NULL) + var);
87 #else
88   return var;
89 #endif
90 }
91
92 static unsigned int decode_opline(unsigned int last, char** p, unsigned int* l) {
93   unsigned int opline;
94   if (last < 0xff-1) {
95     opline = decode(p, l);
96     if (opline == 0xff) return (unsigned int)-1;
97   } else if (last < 0xffff-1) {
98     opline = decode16(p, l);
99     if (opline == 0xffff) return (unsigned int)-1;
100   } else {
101     opline = decode32(p, l);
102   }
103   if (opline >= last) {
104     zend_bailout();
105   }
106   return opline;
107 }
108
109 static char* decode_zstr(char** p, unsigned int* l) {
110   char *s = *p;
111   unsigned int len = 0;
112   while (s[len] != '\0') {
113     len++;
114     if (len > (*l)) {
115       zend_bailout();
116     }
117   }
118   if (len == 0) {
119     (*p)++;
120     (*l)--;
121     return NULL;
122   } else {
123     char *str = emalloc(len+1);
124     memcpy(str, *p, len+1);
125     *p += len+1;
126     *l -= len+1;
127     return str;
128   }
129 }
130
131 static char* decode_zstr_noalloc(char** p, unsigned int* l) {
132   char *s = *p;
133   unsigned int len = 0;
134   while (s[len] != '\0') {
135     len++;
136     if (len > (*l)) {
137       zend_bailout();
138     }
139   }
140   if (len == 0) {
141     (*p)++;
142     (*l)--;
143     return NULL;
144   } else {
145     *p += len+1;
146     *l -= len+1;
147     return s;
148   }
149 }
150
151 #if MMC_ENCODER_VERSION < 2
152 static char* decode_filename(char** p, unsigned int* l TSRMLS_DC) {
153   char *s = *p;
154   unsigned int len = 0;
155   while (s[len] != '\0') {
156     len++;
157     if (len > (*l)) {
158       zend_bailout();
159     }
160   }
161   if (len == 0) {
162     (*p)++;
163     (*l)--;
164     return NULL;
165   } else {
166     if (((loader_data*)MMCG(mem))->filename == NULL ||
167         strcmp(((loader_data*)MMCG(mem))->filename,*p) != 0) {
168       char* old = CG(compiled_filename);
169       ((loader_data*)MMCG(mem))->filename = zend_set_compiled_filename(*p TSRMLS_CC);
170       CG(compiled_filename) = old;
171     }
172     *p += len+1;
173     *l -= len+1;
174     return ((loader_data*)MMCG(mem))->filename;
175   }
176 }
177 #endif
178
179 static char* decode_lstr(unsigned int* len, char** p, unsigned int* l) {
180   *len = decode32(p, l);
181   if (*len == 0) {
182     return NULL;
183   } else {
184     char* str;
185     if (*len > *l) {
186       zend_bailout();
187     }
188     str = emalloc((*len)+1);
189     memcpy(str, *p, *len);
190     str[(*len)] = '\0';
191     *p += *len;
192     *l -= *len;
193     return str;
194   }
195 }
196
197 static char* decode_lstr_noalloc(unsigned int* len, char** p, unsigned int* l) {
198   *len = decode32(p, l);
199   if (*len == 0) {
200     return NULL;
201   } else {
202     char* str = *p;
203     if (*len > *l) {
204       zend_bailout();
205     }
206     *p += *len;
207     *l -= *len;
208     return str;
209   }
210 }
211
212 static unsigned char* decode_pstr(char** p, unsigned int* l) {
213   unsigned char c = decode(p, l);
214   if (c == 0) {
215     return NULL;
216   } else {
217     unsigned char *str;
218     if (c > *l) {
219       zend_bailout();
220     }
221     str = emalloc(c+1);
222     str[0] = c;
223     memcpy(&str[1], *p, c);
224     *p += c;
225     *l -= c;
226     return str;
227   }
228 }
229
230 static double decode_double(char** p, unsigned int* l) {
231   unsigned char sign;
232   int exp;
233   unsigned int i1, i2;
234   double d;
235
236   sign = decode(p, l);
237   exp = decode32(p, l);
238   i1 = decode32(p, l);
239   i2 = decode32(p, l);
240   d = ldexp((((double)i2 / 4294967296.0) + (double)i1) / 4294967296.0, exp);
241   if (sign) {
242     d = -d;
243   }
244   return d;
245 }
246
247 typedef void* (*decode_bucket_t)(void* to, char**, unsigned int* TSRMLS_DC);
248
249 #define decode_zval_hash(to, p, l) decode_hash(to, sizeof(zval*), (decode_bucket_t)decode_zval_ptr, p, l TSRMLS_CC)
250 #define decode_zval_hash_noref(to, p, l) decode_hash(to, sizeof(zval*), (decode_bucket_t)decode_zval_ptr_noref, p, l TSRMLS_CC)
251
252 static HashTable* decode_hash(HashTable* to, int size, decode_bucket_t decode_bucket, char**p, unsigned int* l TSRMLS_DC);
253 static zval* decode_zval_ptr(zval* to, char** p, unsigned int* l TSRMLS_DC);
254
255 static zval* decode_zval(zval* to, int refs, char** p, unsigned int* l TSRMLS_DC) {
256   to->type     = decode(p ,l);
257   if (refs) {
258     to->is_ref = decode(p, l);
259     to->refcount = decode32(p, l);
260   } else {
261     to->is_ref   = 1;
262     to->refcount = 2;
263   }
264   switch (to->type & ~IS_CONSTANT_INDEX) {
265     case IS_NULL:
266       break;
267     case IS_BOOL:
268       to->value.lval = decode(p, l);
269       break;
270     case IS_LONG:
271       {
272   int x = decode32(p,l);
273         to->value.lval = x;
274       }
275       break;
276     case IS_DOUBLE:
277       to->value.dval = decode_double(p, l);
278       break;
279     case IS_CONSTANT:
280     case IS_STRING:
281 /*???    case FLAG_IS_BC:*/
282       to->value.str.val = decode_lstr((unsigned int*)&to->value.str.len, p, l);
283       if (to->value.str.val == NULL) {
284         to->value.str.val = empty_string;
285       }
286       break;
287     case IS_ARRAY:
288     case IS_CONSTANT_ARRAY:
289       to->value.ht = decode_zval_hash(NULL, p ,l);
290       if (to->value.ht) {
291         to->value.ht->pDestructor = ZVAL_PTR_DTOR;
292       } else {
293         ALLOC_HASHTABLE(to->value.ht);
294         zend_hash_init(to->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
295       }
296       break;
297     case IS_OBJECT:
298     case IS_RESOURCE:
299       /*???*/
300     default:
301       zend_bailout();
302       break;
303   }
304   return to;
305 }
306
307 static zval* decode_zval_ptr(zval* to, char** p, unsigned int* l TSRMLS_DC) {
308   if (to == NULL) {
309     ALLOC_ZVAL(to);
310   }
311   decode_zval(to, 1, p, l TSRMLS_CC);
312   return to;
313 }
314
315 static zval* decode_zval_ptr_noref(zval* to, char** p, unsigned int* l TSRMLS_DC) {
316   if (to == NULL) {
317     ALLOC_ZVAL(to);
318   }
319   decode_zval(to, 1, p, l TSRMLS_CC);
320   to->is_ref   = 0;
321   to->refcount = 1;
322   return to;
323 }
324
325 static void decode_znode(znode* to, unsigned int vars_count, char** p, unsigned int* l TSRMLS_DC) {
326   to->op_type = decode(p, l);
327   if (to->op_type == IS_CONST) {
328     decode_zval(&to->u.constant, 0, p, l TSRMLS_CC);
329     to->u.constant.is_ref = 1;
330     to->u.constant.refcount = 2;
331   } else if (to->op_type == IS_VAR ||
332              to->op_type == IS_TMP_VAR) {
333     to->u.var = decode_var(vars_count, p, l);
334   } else if (to->op_type != IS_UNUSED) {
335     zend_bailout();
336   }
337 }
338
339 static HashTable* decode_hash(HashTable* to, int size, decode_bucket_t decode_bucket, char** p, unsigned int* l TSRMLS_DC) {
340   unsigned int n;
341   void *data = NULL;
342
343   if (size != sizeof(void*)) {
344     data = do_alloca(size);
345   }
346   n = decode32(p, l);
347   if (to == NULL) {
348     if (n == 0 ) return NULL;
349     ALLOC_HASHTABLE(to);
350     zend_hash_init(to, 0, NULL, NULL, 0);
351   }
352   while (n > 0) {
353     void* x;
354     char* s;
355     unsigned int len;
356
357     s = decode_lstr_noalloc(&len, p, l);
358     if (s == NULL) {
359       len = decode32(p, l);
360     }
361     if (size == sizeof(void*)) {
362       x = decode_bucket(NULL, p, l TSRMLS_CC);
363       if (s != NULL) {
364         zend_hash_add(to, s, len, &x, size, NULL);
365       } else {
366         zend_hash_index_update(to, len, &x, size, NULL);
367       }
368     } else {
369       decode_bucket(data, p, l TSRMLS_CC);
370       if (s != NULL) {
371         zend_hash_add(to, s, len, data, size, NULL);
372       } else {
373         zend_hash_index_update(to, len, data, size, NULL);
374       }
375     }
376     --n;
377   }
378   if (size != sizeof(void*)) {
379     free_alloca(data);
380   }
381   return to;
382 }
383
384 static void call_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC) {
385   if (extension->op_array_ctor) {
386     extension->op_array_ctor(op_array);
387   }
388 }
389
390 static zend_op_array* decode_op_array(zend_op_array *to, char** p, unsigned int* l TSRMLS_DC) {
391   char c;
392   zend_op *opline;
393   zend_op *end;
394 #ifdef ZEND_ENGINE_2
395   char* scope_name;
396   int   scope_name_len;
397 #endif
398
399   c = decode(p, l);
400   if (c == ZEND_INTERNAL_FUNCTION) {
401     if (to == NULL) {
402       to = (zend_op_array*)emalloc(sizeof(zend_internal_function));
403     }
404     memset(to, 0, sizeof(zend_internal_function));
405   } else if (c == ZEND_USER_FUNCTION) {
406     if (to == NULL) {
407       to = (zend_op_array*)emalloc(sizeof(zend_op_array));
408     }
409     memset(to, 0, sizeof(zend_op_array));
410     zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) call_op_array_ctor_handler, to TSRMLS_CC);
411   } else {
412     zend_bailout();
413   }
414   to->type = c;
415 #ifdef ZEND_ENGINE_2
416   to->num_args = decode32(p, l);
417   if (to->num_args > 0) {
418     zend_uint i;
419     to->arg_info = (zend_arg_info*)emalloc(to->num_args * sizeof(zend_arg_info));
420     for (i = 0; i < to->num_args; i++) {
421       to->arg_info[i].name = decode_lstr(&to->arg_info[i].name_len, p ,l);
422       to->arg_info[i].class_name = decode_lstr(&to->arg_info[i].class_name_len, p ,l);
423       to->arg_info[i].allow_null = decode(p, l);
424       to->arg_info[i].pass_by_reference = decode(p, l);
425     }
426   } else {
427     to->arg_info = NULL;
428   }
429   to->pass_rest_by_reference = decode(p, l);
430 #else
431   to->arg_types     = decode_pstr(p, l);
432 #endif
433   to->function_name = decode_zstr(p, l);
434 #ifdef ZEND_ENGINE_2
435         to->scope            = MMCG(class_entry);
436         to->fn_flags         = decode32(p, l);
437         scope_name = decode_lstr((unsigned int*)&scope_name_len, p, l);
438         if (to->scope == NULL && scope_name != NULL)
439         {
440                 if (zend_hash_find(CG(class_table),
441                         (void *)scope_name, scope_name_len,
442                         (void **)&to->scope) == SUCCESS)
443                 {
444                         to->scope = *(zend_class_entry**)to->scope;
445                 }
446                 else
447                 {
448 /*???
449                         debug_printf("[%d] EACCELERATOR can't restore parent class "
450                                 "\"%s\" of function \"%s\"\n", getpid(),
451                                 (char*)scope_name, to->function_name);
452 */
453                                 to->scope = NULL;
454                 }
455         }
456         if (to->scope != NULL)
457         {
458                 unsigned int len = strlen(to->function_name);
459                 char *lcname = zend_str_tolower_dup(to->function_name, len);
460                 /*
461                  * HOESH: As explained in restore_op_array()!
462                  */
463                 if  (
464                                 to->scope->name_length == len &&
465                                 memcmp(to->scope->name, lcname, len) == 0 &&
466                                 (
467                                         to->scope->constructor == NULL || // case 0)
468                                         to->scope->constructor->type == ZEND_INTERNAL_FUNCTION || // case A)
469                                         to->scope->constructor->op_array.scope->name_length != len || // case B)
470                                         memcmp(to->scope->constructor->op_array.scope->name, lcname, len) != 0
471                                 )
472                         )
473                 {
474                         to->scope->constructor = (zend_function*)to;
475                 }
476                 else if (*lcname == '_' && *(lcname+1) == '_')
477                 {
478                         if (len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 &&
479                                 memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
480                         {
481                                 to->scope->constructor = (zend_function*)to;
482                         }
483                         else if (len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1 &&
484                                 memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
485                         {
486                                 to->scope->destructor = (zend_function*)to;
487                         }
488                         else if (len == sizeof(ZEND_CLONE_FUNC_NAME)-1 &&
489                                 memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
490                         {
491                                 to->scope->clone = (zend_function*)to;
492                         }
493                         else if (len == sizeof(ZEND_GET_FUNC_NAME)-1 &&
494                                 memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
495                         {
496                                 to->scope->__get = (zend_function*)to;
497                         }
498                         else if (len == sizeof(ZEND_SET_FUNC_NAME)-1 &&
499                                 memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
500                         {
501                                 to->scope->__set = (zend_function*)to;
502                         }
503                         else if (len == sizeof(ZEND_CALL_FUNC_NAME)-1 &&
504                                 memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
505                         {
506                                 to->scope->__call = (zend_function*)to;
507                         }
508                 }
509                 efree(lcname);
510         }
511 #endif
512   if (to->type == ZEND_INTERNAL_FUNCTION) {
513     return to;
514   }
515   to->T = decode32(p, l);
516 #ifdef ZEND_ENGINE_2
517   to->uses_this = decode(p, l);
518 #else
519   to->uses_globals = decode(p, l);
520 #endif
521   to->return_reference = decode(p, l);
522
523   to->last = decode32(p, l);
524   to->size = to->last;
525   if (to->last > 0) {
526     to->last_brk_cont = decode32(p, l);
527     if (to->last_brk_cont > 0) {
528       zend_uint i;
529       to->brk_cont_array = emalloc(sizeof(zend_brk_cont_element)*to->last_brk_cont);
530       for (i = 0; i < to->last_brk_cont; i++) {
531         to->brk_cont_array[i].brk = decode_opline(to->last, p, l);
532         to->brk_cont_array[i].cont = decode_opline(to->last, p, l);
533         to->brk_cont_array[i].parent = decode_opline(to->last_brk_cont, p, l);
534       }
535     } else {
536       to->brk_cont_array = NULL;
537     }
538 #ifdef ZEND_ENGINE_2
539         to->last_try_catch = decode32(p, l);
540         if (to->last_try_catch > 0)
541         {
542                 zend_uint i;
543                 to->try_catch_array = emalloc(sizeof(zend_try_catch_element)*to->last_try_catch);
544                 for (i = 0; i < to->last_try_catch; i++)
545                 {
546                         to->try_catch_array[i].try_op = decode_opline(to->last, p, l);
547                         to->try_catch_array[i].catch_op = decode_opline(to->last, p, l);
548 //                      to->try_catch_array[i].parent = decode_opline(to->last_brk_cont, p, l);
549                 }
550         }
551         else
552         {
553                 to->try_catch_array = NULL;
554 }
555 #endif
556     to->opcodes = emalloc(sizeof(zend_op)*to->last);
557     memset(to->opcodes, 0, sizeof(zend_op)*to->last);
558     opline = to->opcodes;
559     end = opline + to->last;
560     for (;opline < end; opline++) {
561       const opcode_dsc* op_dsc;
562       opline->opcode = decode(p, l);
563       op_dsc = get_opcode_dsc(opline->opcode);
564       if (op_dsc == NULL) {
565         zend_bailout();
566       } else {
567         unsigned int ops = op_dsc->ops;
568 #ifdef ZEND_ENGINE_2
569 #ifdef HAVE_EACCELERATOR_STANDALONE_LOADER
570         opline->handler = zend_opcode_handlers[opline->opcode];
571 #else
572         opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
573 #endif
574 #endif
575 #if MMC_ENCODER_VERSION < 2
576         opline->lineno = decode32(p, l);
577 #else
578         if (((loader_data*)MMCG(mem))->version < 2) {
579           opline->lineno = decode32(p, l);
580         }
581         opline->lineno = ((loader_data*)MMCG(mem))->lineno;
582 #endif
583         opline->extended_value = 0;
584         opline->result.op_type = IS_UNUSED;
585         opline->op1.op_type    = IS_UNUSED;
586         opline->op2.op_type    = IS_UNUSED;
587
588         switch (ops & EXT_MASK) {
589           case EXT_UNUSED:
590             break;
591           case EXT_STD:
592           case EXT_FCALL:
593           case EXT_ARG:
594           case EXT_IFACE:
595             opline->extended_value = decode32(p, l);
596             break;
597           case EXT_SEND:
598           case EXT_SEND_NOREF:
599           case EXT_INIT_FCALL:
600           case EXT_FETCH:
601           case EXT_CAST:
602           case EXT_DECLARE:
603           case EXT_FCLASS:
604           case EXT_BIT:
605           case EXT_ISSET:
606           case EXT_ASSIGN:
607             opline->extended_value = decode(p, l);
608             break;
609           case EXT_FE: /* EXT_FE is added at MMC_ENCODER_VERSION = 3 to support php 4.3.10 */
610 #if MMC_ENCODER_VERSION >= 3
611             if (((loader_data*)MMCG(mem))->version >= 3) {
612               opline->extended_value = decode(p, l);
613             }
614 #endif
615             break;
616           case EXT_OPLINE:
617             opline->extended_value = decode_opline(to->last, p, l);
618             break;
619           case EXT_CLASS:
620             opline->extended_value = decode_var(to->T, p, l);
621             break;
622           default:
623             zend_bailout();
624             break;
625         }
626
627 #if MMC_ENCODER_VERSION >= 3 && defined(ZEND_FE_FETCH_WITH_KEY) && !defined(ZEND_ENGINE_2)
628         /* correct ZEND_FE_FETCH's extended value with old version (1,2) */
629         if (opline->opcode == ZEND_FE_FETCH) {
630           if (((loader_data*)MMCG(mem))->version < 3) {
631             opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
632           }
633         }
634 #endif
635         switch (ops & RES_MASK) {
636           case RES_UNUSED:
637             break;
638           case RES_TMP:
639             opline->result.op_type = IS_TMP_VAR;
640             opline->result.u.var = decode_var(to->T, p, l);
641             break;
642           case RES_CLASS:
643             opline->result.u.var = decode_var(to->T, p, l);
644             opline->result.op_type = IS_CONST;
645             break;
646           case RES_VAR:
647             opline->result.op_type = IS_VAR;
648             opline->result.u.var = decode_var(to->T, p, l);
649             opline->result.u.EA.type = 0;
650             if (decode(p, l)) {
651               opline->result.u.EA.type |= EXT_TYPE_UNUSED;
652             }
653             break;
654           case RES_STD:
655             decode_znode(&opline->result, to->T, p, l TSRMLS_CC);
656             if (opline->result.op_type == IS_VAR) {
657               opline->result.u.EA.type = 0;
658               if (decode(p, l)) {
659                 opline->result.u.EA.type |= EXT_TYPE_UNUSED;
660               }
661             }
662             break;
663           default:
664             zend_bailout();
665             break;
666         }
667         switch (ops & OP1_MASK) {
668           case OP1_UNUSED:
669             break;
670           case OP1_OPLINE:
671             opline->op1.u.opline_num = decode_opline(to->last, p, l);
672             break;
673           case OP1_BRK:
674           case OP1_CONT:
675             opline->op1.u.opline_num = decode_opline(to->last_brk_cont, p, l);
676             break;
677           case OP1_CLASS:
678             opline->op1.u.var = decode_var(to->T, p, l);
679             break;
680           case OP1_UCLASS:
681             opline->op1.op_type = decode(p, l);
682             if (opline->op1.op_type != IS_UNUSED) {
683               opline->op1.u.var = decode_var(to->T, p, l);
684             }
685             break;
686           case OP1_TMP:
687             opline->op1.op_type = IS_TMP_VAR;
688             opline->op1.u.var = decode_var(to->T, p, l);
689             break;
690           case OP1_VAR:
691             opline->op1.op_type = IS_VAR;
692             opline->op1.u.var = decode_var(to->T, p, l);
693             break;
694           case OP1_ARG:
695             opline->op1.op_type = IS_CONST;
696             opline->op1.u.constant.type = IS_LONG;
697             opline->op1.u.constant.value.lval = decode32(p, l);
698             break;
699 #ifdef ZEND_ENGINE_2
700           case OP1_JMPADDR:
701             opline->op1.u.jmp_addr = to->opcodes + decode_opline(to->last, p, l);
702             break;
703 #endif
704           case OP1_STD:
705             decode_znode(&opline->op1, to->T, p, l TSRMLS_CC);
706             break;
707           default:
708             zend_bailout();
709             break;
710         }
711         switch (ops & OP2_MASK) {
712           case OP2_UNUSED:
713             break;
714           case OP2_OPLINE:
715             opline->op2.u.opline_num = decode_opline(to->last, p, l);
716             break;
717           case OP2_ARG:
718             opline->op2.u.opline_num = decode32(p, l);
719             break;
720           case OP2_ISSET:
721           case OP2_INCLUDE:
722             opline->op2.op_type = IS_CONST;
723             opline->op2.u.constant.type = IS_LONG;
724             opline->op2.u.constant.value.lval = decode(p, l);
725             break;
726           case OP2_FETCH:
727 #ifdef ZEND_ENGINE_2
728             opline->op2.u.EA.type = decode(p, l);
729             if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) {
730               opline->op2.u.var = decode_var(to->T, p, l);
731             }
732 #else
733             opline->op2.u.fetch_type = decode(p, l);
734 #endif
735             break;
736           case OP2_CLASS:
737             opline->op2.u.var = decode_var(to->T, p, l);
738             break;
739           case OP2_TMP:
740             opline->op2.op_type = IS_TMP_VAR;
741             opline->op2.u.var = decode_var(to->T, p, l);
742             break;
743           case OP2_VAR:
744             opline->op2.op_type = IS_VAR;
745             opline->op2.u.var = decode_var(to->T, p, l);
746             break;
747 #ifdef ZEND_ENGINE_2
748           case OP2_JMPADDR:
749             opline->op2.u.jmp_addr = to->opcodes + decode_opline(to->last, p, l);
750             break;
751 #endif
752           case OP2_STD:
753             decode_znode(&opline->op2, to->T, p, l TSRMLS_CC);
754             break;
755           default:
756             zend_bailout();
757             break;
758         }
759       }
760     }
761   } else {
762     to->opcodes = NULL;
763   }
764
765 #ifdef ZEND_ENGINE_2
766   to->static_variables = decode_zval_hash(NULL, p, l);
767 #else
768   to->static_variables = decode_zval_hash_noref(NULL, p, l);
769 #endif
770   if (to->static_variables) {
771     to->static_variables->pDestructor = ZVAL_PTR_DTOR;
772   }
773 #if MMC_ENCODER_VERSION < 2
774   to->filename = decode_filename(p, l TSRMLS_CC);
775 #else
776   if (((loader_data*)MMCG(mem))->version < 2) {
777     to->filename = decode_zstr(p, l);
778     efree(to->filename);
779   }
780   to->filename = ((loader_data*)MMCG(mem))->filename;
781 #endif
782 #ifdef ZEND_ENGINE_2
783   to->line_start = decode32(p, l);
784   to->line_end = decode32(p, l);
785   to->doc_comment = decode_lstr(&to->doc_comment_len, p, l);
786 #endif
787   to->start_op = to->opcodes;
788   to->current_brk_cont = 0xffffffff;
789   to->backpatch_count  = 0;
790   to->done_pass_two    = 1;
791   to->refcount = emalloc(sizeof(*to->refcount));
792    *to->refcount=1;
793   return to;
794 }
795
796
797 #ifdef ZEND_ENGINE_2
798 static zend_property_info* decode_property_info(zend_property_info* to, char** p, unsigned int* l TSRMLS_DC) {
799   if (to == NULL) {
800     to = emalloc(sizeof(zend_property_info));
801   }
802   to->flags = decode32(p, l);
803   to->name = decode_lstr((unsigned int*)&to->name_length, p, l);
804   return to;
805 }
806 #endif
807
808 static zend_class_entry* decode_class_entry(zend_class_entry* to, char** p, unsigned int* l TSRMLS_DC) {
809   char c;
810   zend_class_entry* old;
811   char*             s;
812   unsigned int      len;
813
814   c = decode(p, l);
815   if (c == ZEND_USER_CLASS) {
816     if (to == NULL) {
817       to = emalloc(sizeof(zend_class_entry));
818     }
819     memset(to, 0, sizeof(zend_class_entry));
820   } else {
821     zend_bailout();
822   }
823   to->type = c;
824   to->name = decode_lstr(&to->name_length, p ,l);
825 #ifdef ZEND_ENGINE_2
826   to->ce_flags = decode32(p ,l);
827   to->num_interfaces = decode32(p, l);
828   if (to->num_interfaces > 0) {
829     to->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*to->num_interfaces);
830   } else {
831     to->interfaces = NULL;
832   }
833   to->create_object = NULL;
834 #endif
835
836   to->parent      = NULL;
837   s = decode_lstr(&len, p, l);
838   if (s != NULL) {
839 #ifdef ZEND_ENGINE_2
840         char* r;
841         r = zend_str_tolower_dup(s, len);
842     if (zend_hash_find(CG(class_table), r, len+1, (void **)&to->parent) != SUCCESS)
843 #else
844         if (zend_hash_find(CG(class_table), s, len+1, (void **)&to->parent) != SUCCESS)
845 #endif
846         {
847       to->parent = NULL;
848     } else {
849 #ifdef ZEND_ENGINE_2
850           /*
851            * HOESH: See restore_class_entry() on details.
852            */
853           to->parent = *(zend_class_entry**)to->parent;
854           to->constructor  = to->parent->constructor;
855           to->destructor  = to->parent->destructor;
856           to->clone  = to->parent->clone;
857           to->__get  = to->parent->__get;
858       to->__set  = to->parent->__set;
859       to->__call = to->parent->__call;
860           to->create_object = to->parent->create_object;
861 #else
862           to->handle_property_get  = to->parent->handle_property_get;
863       to->handle_property_set  = to->parent->handle_property_set;
864       to->handle_function_call = to->parent->handle_function_call;
865 #endif
866     }
867 #ifdef ZEND_ENGINE_2
868         efree(r);
869 #endif
870     efree(s);
871   }
872
873   old = MMCG(class_entry);
874   MMCG(class_entry) = to;
875
876 #ifdef ZEND_ENGINE_2
877   to->refcount = 1;
878
879 #if MMC_ENCODER_VERSION < 2
880   to->line_start = decode32(p, l);
881   to->line_end = decode32(p, l);
882   to->filename = decode_filename(p, l TSRMLS_CC);
883 #else
884   if (((loader_data*)MMCG(mem))->version < 2) {
885     to->line_start = decode32(p, l);
886     to->line_end = decode32(p, l);
887     to->filename = decode_zstr(p, l);
888     efree(to->filename);
889   }
890   to->line_start = ((loader_data*)MMCG(mem))->lineno;
891   to->line_end = ((loader_data*)MMCG(mem))->lineno;
892   to->filename = ((loader_data*)MMCG(mem))->filename;
893 #endif
894   to->doc_comment = decode_lstr(&to->doc_comment_len, p, l);
895
896   zend_hash_init(&to->constants_table, 0, NULL, ZVAL_PTR_DTOR, 0);
897   decode_zval_hash(&to->constants_table, p, l);
898
899   zend_hash_init(&to->default_properties, 0, NULL, ZVAL_PTR_DTOR, 0);
900   decode_zval_hash(&to->default_properties, p, l);
901
902 /*???FIXME
903   zend_hash_init_ex(&to->properties_info, 0, NULL, (dtor_func_t)zend_destroy_property_info, 0, 0);
904 */
905   zend_hash_init_ex(&to->properties_info, 0, NULL, (dtor_func_t)NULL, 0, 0);
906   decode_hash(&to->properties_info, sizeof(zend_property_info), (decode_bucket_t)decode_property_info, p, l TSRMLS_CC);
907
908   ALLOC_HASHTABLE(to->static_members);
909   zend_hash_init_ex(to->static_members, 0, NULL, ZVAL_PTR_DTOR, 0, 0);
910   decode_zval_hash(to->static_members, p, l);
911
912   {
913     Bucket *q = to->properties_info.pListHead;
914     while (q != NULL) {
915       zend_property_info* x = (zend_property_info*)q->pData;
916       Bucket * y = NULL;
917       if ((x->flags & ZEND_ACC_STATIC) && to->static_members != NULL && to->static_members->nNumOfElements > 0) {
918         y = to->static_members->pListHead;
919       } else if ((x->flags & ZEND_ACC_STATIC) == 0 && to->default_properties.nNumOfElements > 0) {
920         y = to->default_properties.pListHead;
921       }
922       while (y != NULL) {
923         if ((int)y->nKeyLength == x->name_length+1 &&
924              memcmp(y->arKey, x->name, x->name_length+1) == 0) {
925           x->h = y->h;
926           break;
927         }
928         y = y->pListNext;
929       }
930       q = q->pListNext;
931     }
932   }
933
934 #else
935   to->refcount = emalloc(sizeof(*to->refcount));
936   *to->refcount = 1;
937
938   zend_hash_init(&to->default_properties, 0, NULL, ZVAL_PTR_DTOR, 0);
939   decode_zval_hash_noref(&to->default_properties, p, l);
940 #endif
941   zend_hash_init(&to->function_table, 0, NULL, ZEND_FUNCTION_DTOR, 0);
942   decode_hash(&to->function_table, sizeof(zend_op_array), (decode_bucket_t)decode_op_array, p, l TSRMLS_CC);
943   to->constants_updated = 0;
944
945 #ifdef ZEND_ENGINE_2
946   {
947     zend_function *f;
948     Bucket *p;
949     int fname_len, cname_len;
950     char *fname_lc, *cname_lc;
951     union _zend_function *old_ctor;
952
953     old_ctor = to->constructor;
954     cname_len = to->name_length;
955     cname_lc  = zend_str_tolower_dup(to->name, cname_len);
956
957     p = to->function_table.pListHead;
958     while (p != NULL) {
959       f         = p->pData;
960       fname_len = strlen(f->common.function_name);
961       fname_lc  = zend_str_tolower_dup(f->common.function_name, fname_len);
962
963       if (fname_len == cname_len && !memcmp(fname_lc, cname_lc, fname_len)
964                  && to->constructor == old_ctor && f->common.scope != to->parent) 
965                 to->constructor = (zend_function*)f;             
966           else if (fname_lc[0] == '_' && fname_lc[1] == '_' && f->common.scope != to->parent)
967       {
968         if (fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
969           to->constructor = (zend_function*)f;
970         else if (fname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
971           to->destructor = (zend_function*)f;
972         else if (fname_len == sizeof(ZEND_CLONE_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
973           to->clone = (zend_function*)f;
974         else if (fname_len == sizeof(ZEND_GET_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
975           to->__get = (zend_function*)f;
976         else if (fname_len == sizeof(ZEND_SET_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
977           to->__set = (zend_function*)f;
978         else if (fname_len == sizeof(ZEND_CALL_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
979           to->__call = (zend_function*)f;
980       }
981       efree(fname_lc);
982       p = p->pListNext;
983     }
984     efree(cname_lc);
985   }
986 #endif
987
988   MMCG(class_entry) = old;
989
990   return to;
991 }
992
993 zend_op_array* eaccelerator_load(char* src, int src_len TSRMLS_DC) {
994   zval func;
995   zval gzstring;
996   zval retval;
997   zval param;
998   zval *params[1];
999   zend_op_array* to = NULL;
1000   zend_bool error_reported = 0;
1001
1002   if (!zend_hash_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress"))) {
1003     zend_error(E_ERROR, "eAccelerator Loader requires php_zlib extension\n");
1004     return NULL;
1005   }
1006
1007   ZVAL_STRING(&func, "base64_decode", 0);
1008   INIT_ZVAL(param);
1009   params[0] = &param;
1010   ZVAL_STRINGL(params[0], src, src_len, 0);
1011   if (call_user_function(CG(function_table), (zval**)NULL, &func, &gzstring, 1, params TSRMLS_CC) == SUCCESS &&
1012       gzstring.type == IS_STRING) {
1013     ZVAL_STRING(&func, "gzuncompress", 0);
1014     params[0] = &gzstring;
1015     if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, 1, params TSRMLS_CC) == SUCCESS &&
1016         retval.type == IS_STRING) {
1017       zend_bool old_in_compilation = CG(in_compilation);
1018       zend_bool old_in_execution   = EG(in_execution);
1019       zval_dtor(&gzstring);
1020       zend_try {
1021         char*        p = retval.value.str.val;
1022         unsigned int l = retval.value.str.len;
1023         char *s;
1024         unsigned char c;
1025         unsigned int  v;
1026
1027         s = decode_zstr_noalloc(&p, &l);
1028         if (s != NULL && strcmp(s,"EACCELERATOR") == 0) {
1029           v = decode32(&p, &l);
1030           if (v <= MMC_ENCODER_VERSION) {
1031             loader_data data;
1032             data.version  = v;
1033             data.filename = NULL;
1034             data.lineno = 0;
1035             MMCG(mem) = (char*)&data;
1036             c = decode(&p, &l);
1037 #ifdef ZEND_ENGINE_2
1038             if (c == 2) {
1039 #else
1040             if (c == 1) {
1041 #endif
1042               MMCG(class_entry) = NULL;
1043 #if MMC_ENCODER_VERSION > 1
1044               if (CG(in_compilation)) {
1045                 data.filename = CG(compiled_filename);
1046                 data.lineno = 0;
1047               } else {
1048                 char* old = CG(compiled_filename);
1049                 if (EG(active_op_array && EG(active_op_array)->filename)) {
1050                   data.filename = zend_set_compiled_filename(EG(active_op_array)->filename TSRMLS_CC);
1051                 }
1052                 CG(compiled_filename) = old;
1053                 data.lineno = zend_get_executed_lineno(TSRMLS_C);
1054               }
1055 #endif
1056               while (1) {
1057                 c = decode(&p, &l);
1058                 if (c == MMC_ENCODER_CLASS) {
1059 #ifdef ZEND_ENGINE_2
1060                   zend_class_entry* x;
1061                   s = decode_lstr_noalloc(&v, &p, &l);
1062                   x = decode_class_entry(NULL, &p, &l TSRMLS_CC);
1063 #else
1064                   zend_class_entry x;
1065                   s = decode_lstr_noalloc(&v, &p, &l);
1066                   decode_class_entry(&x, &p, &l TSRMLS_CC);
1067 #endif
1068                   if ((s[0] == '\000') &&
1069                       zend_hash_exists(CG(class_table), s, v)) {
1070 #ifdef ZEND_ENGINE_2
1071                   } else if (zend_hash_add(CG(class_table), s, v,
1072                       &x, sizeof(zend_class_entry*), NULL) == FAILURE) {
1073 #else
1074                   } else if (zend_hash_add(CG(class_table), s, v,
1075                       &x, sizeof(zend_class_entry), NULL) == FAILURE) {
1076 #endif
1077                     error_reported = 1;
1078                     zend_error(E_ERROR, "Cannot redeclare class %s", s);
1079                   }
1080                 } else if (c == MMC_ENCODER_END) {
1081                   break;
1082                 } else {
1083                   zend_bailout();
1084                 }
1085               }
1086               while (1) {
1087                 c = decode(&p, &l);
1088                 if (c == MMC_ENCODER_FUNCTION) {
1089                   zend_op_array x;
1090                   s = decode_lstr_noalloc(&v, &p, &l);
1091                   decode_op_array(&x, &p, &l TSRMLS_CC);
1092                   if ((s[0] == '\000') &&
1093                       zend_hash_exists(CG(function_table), s, v)) {
1094                   } else if (zend_hash_add(CG(function_table), s, v,
1095                              &x, sizeof(zend_op_array), NULL) == FAILURE) {
1096                     error_reported = 1;
1097                     zend_error(E_ERROR, "Cannot redeclare %s()", s);
1098                   }
1099                 } else if (c == MMC_ENCODER_END) {
1100                   break;
1101                 } else {
1102                   zend_bailout();
1103                 }
1104               }
1105               to = decode_op_array(NULL, &p, &l TSRMLS_CC);
1106               if (l != 0) {
1107                 zend_bailout();
1108               }
1109             } else {
1110               error_reported = 1;
1111               zend_error(E_ERROR, "eAccelerator Loader can't load code. Incorrect Zend Engine version");
1112             }
1113           } else {
1114             error_reported = 1;
1115         &nb