1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #include <stdio.h>
23
24 #include "zend.h"
25 #include "zend_alloc.h"
26 #include "zend_compile.h"
27 #include "zend_extensions.h"
28 #include "zend_API.h"
29
30 #include "zend_vm.h"
31
zend_extension_op_array_ctor_handler(zend_extension * extension,zend_op_array * op_array TSRMLS_DC)32 static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
33 {
34 if (extension->op_array_ctor) {
35 extension->op_array_ctor(op_array);
36 }
37 }
38
zend_extension_op_array_dtor_handler(zend_extension * extension,zend_op_array * op_array TSRMLS_DC)39 static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
40 {
41 if (extension->op_array_dtor) {
42 extension->op_array_dtor(op_array);
43 }
44 }
45
op_array_alloc_ops(zend_op_array * op_array,zend_uint size)46 static void op_array_alloc_ops(zend_op_array *op_array, zend_uint size)
47 {
48 op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op));
49 }
50
init_op_array(zend_op_array * op_array,zend_uchar type,int initial_ops_size TSRMLS_DC)51 void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size TSRMLS_DC)
52 {
53 op_array->type = type;
54
55 if (CG(interactive)) {
56 /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants
57 * will become invalid
58 */
59 initial_ops_size = INITIAL_INTERACTIVE_OP_ARRAY_SIZE;
60 }
61
62 op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint));
63 *op_array->refcount = 1;
64 op_array->last = 0;
65 op_array->opcodes = NULL;
66 op_array_alloc_ops(op_array, initial_ops_size);
67
68 op_array->last_var = 0;
69 op_array->vars = NULL;
70
71 op_array->T = 0;
72
73 op_array->function_name = NULL;
74 op_array->filename = zend_get_compiled_filename(TSRMLS_C);
75 op_array->doc_comment = NULL;
76 op_array->doc_comment_len = 0;
77
78 op_array->arg_info = NULL;
79 op_array->num_args = 0;
80 op_array->required_num_args = 0;
81
82 op_array->scope = NULL;
83
84 op_array->brk_cont_array = NULL;
85 op_array->try_catch_array = NULL;
86 op_array->last_brk_cont = 0;
87
88 op_array->static_variables = NULL;
89 op_array->last_try_catch = 0;
90
91 op_array->this_var = -1;
92
93 op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0;
94
95 op_array->early_binding = -1;
96
97 op_array->last_literal = 0;
98 op_array->literals = NULL;
99
100 op_array->run_time_cache = NULL;
101 op_array->last_cache_slot = 0;
102
103 memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
104
105 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC);
106 }
107
destroy_zend_function(zend_function * function TSRMLS_DC)108 ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC)
109 {
110 switch (function->type) {
111 case ZEND_USER_FUNCTION:
112 destroy_op_array((zend_op_array *) function TSRMLS_CC);
113 break;
114 case ZEND_INTERNAL_FUNCTION:
115 /* do nothing */
116 break;
117 }
118 }
119
zend_function_dtor(zend_function * function)120 ZEND_API void zend_function_dtor(zend_function *function)
121 {
122 TSRMLS_FETCH();
123
124 destroy_zend_function(function TSRMLS_CC);
125 }
126
zend_cleanup_op_array_data(zend_op_array * op_array)127 static void zend_cleanup_op_array_data(zend_op_array *op_array)
128 {
129 if (op_array->static_variables) {
130 zend_hash_clean(op_array->static_variables);
131 }
132 }
133
zend_cleanup_function_data(zend_function * function TSRMLS_DC)134 ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC)
135 {
136 if (function->type == ZEND_USER_FUNCTION) {
137 zend_cleanup_op_array_data((zend_op_array *) function);
138 return ZEND_HASH_APPLY_KEEP;
139 } else {
140 return ZEND_HASH_APPLY_STOP;
141 }
142 }
143
zend_cleanup_function_data_full(zend_function * function TSRMLS_DC)144 ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC)
145 {
146 if (function->type == ZEND_USER_FUNCTION) {
147 zend_cleanup_op_array_data((zend_op_array *) function);
148 }
149 return 0;
150 }
151
cleanup_user_class_data(zend_class_entry * ce TSRMLS_DC)152 static inline void cleanup_user_class_data(zend_class_entry *ce TSRMLS_DC)
153 {
154 /* Clean all parts that can contain run-time data */
155 /* Note that only run-time accessed data need to be cleaned up, pre-defined data can
156 not contain objects and thus are not probelmatic */
157 if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
158 zend_hash_apply(&ce->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC);
159 }
160 if (ce->static_members_table) {
161 int i;
162
163 for (i = 0; i < ce->default_static_members_count; i++) {
164 if (ce->static_members_table[i]) {
165 zval *p = ce->static_members_table[i];
166 ce->static_members_table[i] = NULL;
167 zval_ptr_dtor(&p);
168 }
169 }
170 ce->static_members_table = NULL;
171 }
172 }
173
cleanup_internal_class_data(zend_class_entry * ce TSRMLS_DC)174 static inline void cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC)
175 {
176 if (CE_STATIC_MEMBERS(ce)) {
177 int i;
178
179 for (i = 0; i < ce->default_static_members_count; i++) {
180 zval_ptr_dtor(&CE_STATIC_MEMBERS(ce)[i]);
181 }
182 efree(CE_STATIC_MEMBERS(ce));
183 #ifdef ZTS
184 CG(static_members_table)[(zend_intptr_t)(ce->static_members_table)] = NULL;
185 #else
186 ce->static_members_table = NULL;
187 #endif
188 }
189 }
190
zend_cleanup_internal_class_data(zend_class_entry * ce TSRMLS_DC)191 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC)
192 {
193 cleanup_internal_class_data(ce TSRMLS_CC);
194 }
195
zend_cleanup_user_class_data(zend_class_entry ** pce TSRMLS_DC)196 ZEND_API int zend_cleanup_user_class_data(zend_class_entry **pce TSRMLS_DC)
197 {
198 if ((*pce)->type == ZEND_USER_CLASS) {
199 cleanup_user_class_data(*pce TSRMLS_CC);
200 return ZEND_HASH_APPLY_KEEP;
201 } else {
202 return ZEND_HASH_APPLY_STOP;
203 }
204 }
205
zend_cleanup_class_data(zend_class_entry ** pce TSRMLS_DC)206 ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
207 {
208 if ((*pce)->type == ZEND_USER_CLASS) {
209 cleanup_user_class_data(*pce TSRMLS_CC);
210 } else {
211 cleanup_internal_class_data(*pce TSRMLS_CC);
212 }
213 return 0;
214 }
215
_destroy_zend_class_traits_info(zend_class_entry * ce)216 void _destroy_zend_class_traits_info(zend_class_entry *ce)
217 {
218 if (ce->num_traits > 0 && ce->traits) {
219 efree(ce->traits);
220 }
221
222 if (ce->trait_aliases) {
223 size_t i = 0;
224 while (ce->trait_aliases[i]) {
225 if (ce->trait_aliases[i]->trait_method) {
226 if (ce->trait_aliases[i]->trait_method->method_name) {
227 efree((char*)ce->trait_aliases[i]->trait_method->method_name);
228 }
229 if (ce->trait_aliases[i]->trait_method->class_name) {
230 efree((char*)ce->trait_aliases[i]->trait_method->class_name);
231 }
232 efree(ce->trait_aliases[i]->trait_method);
233 }
234
235 if (ce->trait_aliases[i]->alias) {
236 efree((char*)ce->trait_aliases[i]->alias);
237 }
238
239 efree(ce->trait_aliases[i]);
240 i++;
241 }
242
243 efree(ce->trait_aliases);
244 }
245
246 if (ce->trait_precedences) {
247 size_t i = 0;
248
249 while (ce->trait_precedences[i]) {
250 efree((char*)ce->trait_precedences[i]->trait_method->method_name);
251 efree((char*)ce->trait_precedences[i]->trait_method->class_name);
252 efree(ce->trait_precedences[i]->trait_method);
253
254 if (ce->trait_precedences[i]->exclude_from_classes) {
255 efree(ce->trait_precedences[i]->exclude_from_classes);
256 }
257
258 efree(ce->trait_precedences[i]);
259 i++;
260 }
261 efree(ce->trait_precedences);
262 }
263 }
264
destroy_zend_class(zend_class_entry ** pce)265 ZEND_API void destroy_zend_class(zend_class_entry **pce)
266 {
267 zend_class_entry *ce = *pce;
268
269 if (--ce->refcount > 0) {
270 return;
271 }
272 switch (ce->type) {
273 case ZEND_USER_CLASS:
274 if (ce->default_properties_table) {
275 int i;
276
277 for (i = 0; i < ce->default_properties_count; i++) {
278 if (ce->default_properties_table[i]) {
279 zval_ptr_dtor(&ce->default_properties_table[i]);
280 }
281 }
282 efree(ce->default_properties_table);
283 }
284 if (ce->default_static_members_table) {
285 int i;
286
287 for (i = 0; i < ce->default_static_members_count; i++) {
288 if (ce->default_static_members_table[i]) {
289 zval_ptr_dtor(&ce->default_static_members_table[i]);
290 }
291 }
292 efree(ce->default_static_members_table);
293 }
294 zend_hash_destroy(&ce->properties_info);
295 str_efree(ce->name);
296 zend_hash_destroy(&ce->function_table);
297 zend_hash_destroy(&ce->constants_table);
298 if (ce->num_interfaces > 0 && ce->interfaces) {
299 efree(ce->interfaces);
300 }
301 if (ce->info.user.doc_comment) {
302 efree((char*)ce->info.user.doc_comment);
303 }
304
305 _destroy_zend_class_traits_info(ce);
306
307 efree(ce);
308 break;
309 case ZEND_INTERNAL_CLASS:
310 if (ce->default_properties_table) {
311 int i;
312
313 for (i = 0; i < ce->default_properties_count; i++) {
314 if (ce->default_properties_table[i]) {
315 zval_internal_ptr_dtor(&ce->default_properties_table[i]);
316 }
317 }
318 free(ce->default_properties_table);
319 }
320 if (ce->default_static_members_table) {
321 int i;
322
323 for (i = 0; i < ce->default_static_members_count; i++) {
324 zval_internal_ptr_dtor(&ce->default_static_members_table[i]);
325 }
326 free(ce->default_static_members_table);
327 }
328 zend_hash_destroy(&ce->properties_info);
329 str_free(ce->name);
330 zend_hash_destroy(&ce->function_table);
331 zend_hash_destroy(&ce->constants_table);
332 if (ce->num_interfaces > 0) {
333 free(ce->interfaces);
334 }
335 free(ce);
336 break;
337 }
338 }
339
zend_class_add_ref(zend_class_entry ** ce)340 void zend_class_add_ref(zend_class_entry **ce)
341 {
342 (*ce)->refcount++;
343 }
344
destroy_op_array(zend_op_array * op_array TSRMLS_DC)345 ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
346 {
347 zend_literal *literal = op_array->literals;
348 zend_literal *end;
349 zend_uint i;
350
351 if (op_array->static_variables) {
352 zend_hash_destroy(op_array->static_variables);
353 FREE_HASHTABLE(op_array->static_variables);
354 }
355
356 if (op_array->run_time_cache) {
357 efree(op_array->run_time_cache);
358 }
359
360 if (--(*op_array->refcount)>0) {
361 return;
362 }
363
364 efree(op_array->refcount);
365
366 if (op_array->vars) {
367 i = op_array->last_var;
368 while (i > 0) {
369 i--;
370 str_efree(op_array->vars[i].name);
371 }
372 efree(op_array->vars);
373 }
374
375 if (literal) {
376 end = literal + op_array->last_literal;
377 while (literal < end) {
378 zval_dtor(&literal->constant);
379 literal++;
380 }
381 efree(op_array->literals);
382 }
383 efree(op_array->opcodes);
384
385 if (op_array->function_name) {
386 efree((char*)op_array->function_name);
387 }
388 if (op_array->doc_comment) {
389 efree((char*)op_array->doc_comment);
390 }
391 if (op_array->brk_cont_array) {
392 efree(op_array->brk_cont_array);
393 }
394 if (op_array->try_catch_array) {
395 efree(op_array->try_catch_array);
396 }
397 if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
398 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC);
399 }
400 if (op_array->arg_info) {
401 for (i=0; i<op_array->num_args; i++) {
402 str_efree(op_array->arg_info[i].name);
403 if (op_array->arg_info[i].class_name) {
404 str_efree(op_array->arg_info[i].class_name);
405 }
406 }
407 efree(op_array->arg_info);
408 }
409 }
410
init_op(zend_op * op TSRMLS_DC)411 void init_op(zend_op *op TSRMLS_DC)
412 {
413 memset(op, 0, sizeof(zend_op));
414 op->lineno = CG(zend_lineno);
415 SET_UNUSED(op->result);
416 }
417
get_next_op(zend_op_array * op_array TSRMLS_DC)418 zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
419 {
420 zend_uint next_op_num = op_array->last++;
421 zend_op *next_op;
422
423 if (next_op_num >= CG(context).opcodes_size) {
424 if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
425 /* we messed up */
426 zend_printf("Ran out of opcode space!\n"
427 "You should probably consider writing this huge script into a file!\n");
428 zend_bailout();
429 }
430 CG(context).opcodes_size *= 4;
431 op_array_alloc_ops(op_array, CG(context).opcodes_size);
432 }
433
434 next_op = &(op_array->opcodes[next_op_num]);
435
436 init_op(next_op TSRMLS_CC);
437
438 return next_op;
439 }
440
get_next_op_number(zend_op_array * op_array)441 int get_next_op_number(zend_op_array *op_array)
442 {
443 return op_array->last;
444 }
445
get_next_brk_cont_element(zend_op_array * op_array)446 zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
447 {
448 op_array->last_brk_cont++;
449 op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
450 return &op_array->brk_cont_array[op_array->last_brk_cont-1];
451 }
452
zend_update_extended_info(zend_op_array * op_array TSRMLS_DC)453 static void zend_update_extended_info(zend_op_array *op_array TSRMLS_DC)
454 {
455 zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
456
457 while (opline<end) {
458 if (opline->opcode == ZEND_EXT_STMT) {
459 if (opline+1<end) {
460 if ((opline+1)->opcode == ZEND_EXT_STMT) {
461 opline->opcode = ZEND_NOP;
462 opline++;
463 continue;
464 }
465 if (opline+1<end) {
466 opline->lineno = (opline+1)->lineno;
467 }
468 } else {
469 opline->opcode = ZEND_NOP;
470 }
471 }
472 opline++;
473 }
474 }
475
zend_extension_op_array_handler(zend_extension * extension,zend_op_array * op_array TSRMLS_DC)476 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
477 {
478 if (extension->op_array_handler) {
479 extension->op_array_handler(op_array);
480 }
481 }
482
pass_two(zend_op_array * op_array TSRMLS_DC)483 ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
484 {
485 zend_op *opline, *end;
486
487 if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
488 return 0;
489 }
490 if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
491 zend_update_extended_info(op_array TSRMLS_CC);
492 }
493 if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
494 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC);
495 }
496
497 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) {
498 op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var);
499 CG(context).vars_size = op_array->last_var;
500 }
501 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) {
502 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
503 CG(context).opcodes_size = op_array->last;
504 }
505 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != op_array->last_literal) {
506 op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
507 CG(context).literals_size = op_array->last_literal;
508 }
509
510 opline = op_array->opcodes;
511 end = opline + op_array->last;
512 while (opline < end) {
513 if (opline->op1_type == IS_CONST) {
514 opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
515 }
516 if (opline->op2_type == IS_CONST) {
517 opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
518 }
519 switch (opline->opcode) {
520 case ZEND_GOTO:
521 if (Z_TYPE_P(opline->op2.zv) != IS_LONG) {
522 zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
523 }
524 /* break omitted intentionally */
525 case ZEND_JMP:
526 opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
527 break;
528 case ZEND_JMPZ:
529 case ZEND_JMPNZ:
530 case ZEND_JMPZ_EX:
531 case ZEND_JMPNZ_EX:
532 case ZEND_JMP_SET:
533 case ZEND_JMP_SET_VAR:
534 opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num];
535 break;
536 }
537 ZEND_VM_SET_OPCODE_HANDLER(opline);
538 opline++;
539 }
540
541 op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
542 return 0;
543 }
544
print_class(zend_class_entry * class_entry TSRMLS_DC)545 int print_class(zend_class_entry *class_entry TSRMLS_DC)
546 {
547 printf("Class %s:\n", class_entry->name);
548 zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC);
549 printf("End of class %s.\n\n", class_entry->name);
550 return 0;
551 }
552
get_unary_op(int opcode)553 ZEND_API unary_op_type get_unary_op(int opcode)
554 {
555 switch (opcode) {
556 case ZEND_BW_NOT:
557 return (unary_op_type) bitwise_not_function;
558 break;
559 case ZEND_BOOL_NOT:
560 return (unary_op_type) boolean_not_function;
561 break;
562 default:
563 return (unary_op_type) NULL;
564 break;
565 }
566 }
567
get_binary_op(int opcode)568 ZEND_API binary_op_type get_binary_op(int opcode)
569 {
570 switch (opcode) {
571 case ZEND_ADD:
572 case ZEND_ASSIGN_ADD:
573 return (binary_op_type) add_function;
574 break;
575 case ZEND_SUB:
576 case ZEND_ASSIGN_SUB:
577 return (binary_op_type) sub_function;
578 break;
579 case ZEND_MUL:
580 case ZEND_ASSIGN_MUL:
581 return (binary_op_type) mul_function;
582 break;
583 case ZEND_DIV:
584 case ZEND_ASSIGN_DIV:
585 return (binary_op_type) div_function;
586 break;
587 case ZEND_MOD:
588 case ZEND_ASSIGN_MOD:
589 return (binary_op_type) mod_function;
590 break;
591 case ZEND_SL:
592 case ZEND_ASSIGN_SL:
593 return (binary_op_type) shift_left_function;
594 break;
595 case ZEND_SR:
596 case ZEND_ASSIGN_SR:
597 return (binary_op_type) shift_right_function;
598 break;
599 case ZEND_CONCAT:
600 case ZEND_ASSIGN_CONCAT:
601 return (binary_op_type) concat_function;
602 break;
603 case ZEND_IS_IDENTICAL:
604 return (binary_op_type) is_identical_function;
605 break;
606 case ZEND_IS_NOT_IDENTICAL:
607 return (binary_op_type) is_not_identical_function;
608 break;
609 case ZEND_IS_EQUAL:
610 return (binary_op_type) is_equal_function;
611 break;
612 case ZEND_IS_NOT_EQUAL:
613 return (binary_op_type) is_not_equal_function;
614 break;
615 case ZEND_IS_SMALLER:
616 return (binary_op_type) is_smaller_function;
617 break;
618 case ZEND_IS_SMALLER_OR_EQUAL:
619 return (binary_op_type) is_smaller_or_equal_function;
620 break;
621 case ZEND_BW_OR:
622 case ZEND_ASSIGN_BW_OR:
623 return (binary_op_type) bitwise_or_function;
624 break;
625 case ZEND_BW_AND:
626 case ZEND_ASSIGN_BW_AND:
627 return (binary_op_type) bitwise_and_function;
628 break;
629 case ZEND_BW_XOR:
630 case ZEND_ASSIGN_BW_XOR:
631 return (binary_op_type) bitwise_xor_function;
632 break;
633 case ZEND_BOOL_XOR:
634 return (binary_op_type) boolean_xor_function;
635 break;
636 default:
637 return (binary_op_type) NULL;
638 break;
639 }
640 }
641
642 /*
643 * Local variables:
644 * tab-width: 4
645 * c-basic-offset: 4
646 * indent-tabs-mode: t
647 * End:
648 */
649