Bug Summary

File:rootdir/src/webserver/src/php_syntree.cpp
Warning:line 1037, column 1
Potential leak of memory pointed to by 'decl_node'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name php_syntree.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src/webserver/src -fcoverage-compilation-dir=/rootdir/src/webserver/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I ../../.. -I ../.. -I ../../../src -I ../../../src/libs -I ../../../src/include -D USE_WX_EXTENSIONS -D WITH_LIBPNG -D HAVE_BFD -I /usr/lib/x86_64-linux-gnu/wx/include/gtk3-unicode-3.2 -I /usr/include/wx-3.2 -D _FILE_OFFSET_BITS=64 -D WXUSINGDLL -D __WXGTK__ -D wxUSE_GUI=0 -D WEBSERVERDIR="/usr/share/amule/webserver" -D YY_NO_INPUT -I /usr/include/upnp -D ENABLE_UPNP=1 -I /usr/include/libpng16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-register -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-17-082348-14898-1 -x c++ php_syntree.cpp
1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2005-2011 Froenchenko Leonid ( lfroen@gmail.com / http://www.amule.org )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24//
25
26
27#include <string> // Do_not_auto_remove (g++-4.0.1)
28
29#ifdef PHP_STANDALONE_EN
30 #include <map>
31 #include <list>
32 #include <stdarg.h>
33#else
34 #include "WebServer.h"
35#endif
36
37
38#include "php_syntree.h"
39#include "php_core_lib.h"
40
41
42PHP_SYN_NODE *g_syn_tree_top = 0;
43
44/* scope table */
45PHP_SCOPE_TABLE g_global_scope = 0;
46PHP_SCOPE_TABLE g_current_scope = 0;
47PHP_SCOPE_STACK g_scope_stack = 0;
48
49
50//
51// Known named constant values
52std::map<std::string, int> g_known_const;
53
54static PHP_EXP_NODE *make_zero_exp_node()
55{
56 PHP_EXP_NODE *node = new PHP_EXP_NODE;
57 memset(node, 0, sizeof(PHP_EXP_NODE));
58 return node;
59}
60
61PHP_EXP_NODE *make_const_exp_dnum(int number)
62{
63 PHP_EXP_NODE *node = make_zero_exp_node();
64 node->op = PHP_OP_VAL;
65 node->val_node.type = PHP_VAL_INT;
66 node->val_node.int_val = number;
67
68 return node;
69}
70
71PHP_EXP_NODE *make_const_exp_fnum(float number)
72{
73 PHP_EXP_NODE *node = make_zero_exp_node();
74 node->op = PHP_OP_VAL;
75 node->val_node.type = PHP_VAL_FLOAT;
76 node->val_node.float_val = number;
77
78 return node;
79}
80
81PHP_EXP_NODE *make_const_exp_str(char *s, int unescape)
82{
83 PHP_EXP_NODE *node = make_zero_exp_node();
84 node->op = PHP_OP_VAL;
85 node->val_node.type = PHP_VAL_STRING;
86
87 if ( unescape ) {
88 node->val_node.str_val = (char *)malloc(strlen(s)+1);
89 // copy and unescape string
90 char *p = node->val_node.str_val;
91 while(*s) {
92 if ( *s == '\\' ) {
93 switch ( *(++s) ) {
94 case 'n' : *p++ = '\n'; s++; break;
95 case 't' : *p++ = '\t'; s++; break;
96 default : *p++ = *s++; break;
97 }
98 } else {
99 *p++ = *s++;
100 }
101 }
102 *p = 0;
103 } else {
104 node->val_node.str_val = strdup(s);
105 }
106
107 return node;
108}
109
110PHP_EXP_NODE *make_const_exp_int_obj(void *obj)
111{
112 PHP_EXP_NODE *node = make_zero_exp_node();
113 node->op = PHP_OP_VAL;
114 node->val_node.type = PHP_VAL_INT_DATA;
115 node->val_node.ptr_val = obj;
116
117 return node;
118}
119
120PHP_EXP_NODE *make_exp_1(PHP_EXP_OP op, PHP_EXP_NODE *operand)
121{
122 PHP_EXP_NODE *node = make_zero_exp_node();
123 node->op = op;
124 node->tree_node.left = operand;
125 return node;
126}
127
128PHP_EXP_NODE *make_exp_2(PHP_EXP_OP op, PHP_EXP_NODE *left, PHP_EXP_NODE *right)
129{
130 PHP_EXP_NODE *node = make_zero_exp_node();
131 node->op = op;
132 node->tree_node.left = left;
133 node->tree_node.right = right;
134 return node;
135}
136
137PHP_EXP_NODE *make_exp_2_self(PHP_EXP_OP op, PHP_EXP_NODE *self, PHP_EXP_NODE *right)
138{
139 PHP_EXP_NODE *clone_self = make_zero_exp_node();
140 *clone_self = *self;
141 return make_exp_2(op, clone_self, right);
142}
143
144PHP_EXP_NODE *make_known_const(char *name)
145{
146 int const_id = -1;
147 if ( g_known_const.count(name) ) {
148 const_id = g_known_const[name];
149 }
150 return make_const_exp_dnum(const_id);
151}
152
153//
154// Create function parameter (in declaration)
155//
156PHP_EXP_NODE *make_func_param(PHP_EXP_NODE *list, PHP_EXP_NODE *var_exp_node, char *class_name, int byref)
157{
158 PHP_FUNC_PARAM_DEF *param = new PHP_FUNC_PARAM_DEF;
159 memset(param, 0, sizeof(PHP_FUNC_PARAM_DEF));
160
161 param->si_var = var_exp_node->var_si_node;
162 param->si_var->type = PHP_SCOPE_PARAM;
163 //printf("mark %p->%p as param\n", param->si_var, param->si_var->var);
164
165 param->var = param->si_var->var;
166
167 delete var_exp_node;
168 param->class_name = class_name ? strdup(class_name) : 0;
169 param->byref = byref;
170
171 PHP_EXP_NODE *curr_node = make_const_exp_int_obj(param);
172
173 if ( list ) {
174 PHP_EXP_NODE *p = list;
175 while ( p->next) {
176 p = p->next;
177 }
178 p->next = curr_node;
179 return list;
180 } else {
181 return curr_node;
182 }
183}
184
185/*
186 * Syntax tree generation
187 */
188PHP_SYN_NODE *make_expr_syn_node(PHP_STATMENT_TYPE type, PHP_EXP_NODE *expr)
189{
190 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
191 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
192
193 syn_node->type = type;
194 syn_node->node_expr = expr;
195
196 return syn_node;
197}
198
199PHP_SYN_NODE *make_ifelse_syn_node(PHP_EXP_NODE *expr,
200 PHP_SYN_NODE *then_node, PHP_SYN_NODE *elseif_list, PHP_SYN_NODE *else_node)
201{
202 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
203 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
204
205 syn_node->type = PHP_ST_IF;
206 syn_node->node_if.cond = expr;
207 syn_node->node_if.code_if = then_node;
208
209 if ( elseif_list ) {
210 syn_node->node_if.code_else = elseif_list;
211
212 PHP_SYN_NODE *curr_if = elseif_list;
213 while ( curr_if->node_if.code_else ) {
214 curr_if = curr_if->node_if.code_else;
215 }
216 curr_if->node_if.code_else = else_node;
217 } else {
218 syn_node->node_if.code_else = else_node;
219 }
220 return syn_node;
221}
222
223PHP_SYN_NODE *make_while_loop_syn_node(PHP_EXP_NODE *cond, PHP_SYN_NODE *code, int do_while)
224{
225 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
226 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
227
228 syn_node->type = do_while ? PHP_ST_WHILE : PHP_ST_DO_WHILE;
229 syn_node->node_while.cond = cond;
230 syn_node->node_while.code = code;
231
232 return syn_node;
233}
234
235PHP_SYN_NODE *make_for_syn_node(PHP_EXP_NODE *start, PHP_EXP_NODE *cond,
236 PHP_EXP_NODE *next, PHP_SYN_NODE *code)
237{
238 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
239 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
240
241 syn_node->type = PHP_ST_FOR;
242 syn_node->node_for.do_start = start;
243 syn_node->node_for.cond = cond;
244 syn_node->node_for.do_next = next;
245 syn_node->node_for.code = code;
246
247 return syn_node;
248}
249
250PHP_SYN_NODE *make_foreach_loop_syn_node(PHP_EXP_NODE *elems,
251 PHP_EXP_NODE *i_key, PHP_EXP_NODE *i_val, PHP_SYN_NODE *code, int byref)
252{
253 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
254 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
255
256 syn_node->type = PHP_ST_FOREACH;
257 syn_node->node_foreach.elems = elems;
258 syn_node->node_foreach.code = code;
259 syn_node->node_foreach.i_key = i_key ? i_key->var_si_node : 0;
260 syn_node->node_foreach.i_val = i_val->var_si_node;
261 syn_node->node_foreach.byref = byref;
262
263 if ( i_key ) {
264 delete i_key;
265 }
266 delete i_val;
267
268 return syn_node;
269}
270
271PHP_SYN_NODE *make_func_decl_syn_node(const char *name, PHP_EXP_NODE *param_list)
272{
273 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
3
Memory is allocated
274 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
275
276 syn_node->type = PHP_ST_FUNC_DECL;
277
278 syn_node->func_decl = new PHP_SYN_FUNC_DECL_NODE;
279 memset(syn_node->func_decl, 0, sizeof(PHP_SYN_FUNC_DECL_NODE));
280 syn_node->func_decl->name = strdup(name);
281
282 if ( param_list
3.1
'param_list' is null
) {
4
Taking false branch
283 PHP_EXP_NODE *curr_param = param_list;
284 // count parameters first
285 while ( curr_param ) {
286 syn_node->func_decl->param_count++;
287 curr_param = curr_param->next;
288 }
289 syn_node->func_decl->params = new PHP_FUNC_PARAM_DEF[syn_node->func_decl->param_count];
290 curr_param = param_list;
291 for(int i = 0; param_list; param_list = param_list->next, i++) {
292 syn_node->func_decl->params[i] = *(PHP_FUNC_PARAM_DEF *)param_list->val_node.ptr_val;
293 // param has been copied to array, so it's no longer needed
294 delete (PHP_FUNC_PARAM_DEF *)param_list->val_node.ptr_val;
295 }
296 // dispose linked list as well
297 while ( curr_param ) {
298 PHP_EXP_NODE *p = curr_param->next;
299 delete curr_param;
300 curr_param = p;
301 }
302 }
303
304 return syn_node;
305}
306
307PHP_SYN_NODE *make_class_decl_syn_node()
308{
309 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
310 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
311
312 syn_node->type = PHP_ST_CLASS_DECL;
313
314 syn_node->class_decl = new PHP_SYN_CLASS_DECL_NODE;
315 memset(syn_node->class_decl, 0, sizeof(PHP_SYN_CLASS_DECL_NODE));
316
317 return syn_node;
318}
319
320PHP_SYN_NODE *make_switch_syn_node(PHP_EXP_NODE *cond, PHP_EXP_NODE *case_list)
321{
322 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
323 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
324
325 syn_node->type = PHP_ST_SWITCH;
326
327 //
328 // Bind all statement lists into single one for
329 // simpler execution
330 //
331 PHP_SYN_NODE *stat_list_tail = 0;
332 for(PHP_EXP_NODE *cur_case = case_list; cur_case; cur_case = cur_case->next) {
333 PHP_SYN_NODE *cur_stat_list = cur_case->exp_node->tree_node.syn_right;
334 if ( stat_list_tail ) {
335 while ( stat_list_tail->next_node ) stat_list_tail = stat_list_tail->next_node;
336 stat_list_tail->next_node = cur_stat_list;
337 } else {
338 stat_list_tail = cur_stat_list;
339 }
340 }
341
342 syn_node->node_switch.cond = cond;
343 syn_node->node_switch.case_list = case_list;
344
345 return syn_node;
346}
347
348PHP_VAR_NODE *make_var_node()
349{
350 PHP_VAR_NODE *node = new PHP_VAR_NODE;
351 memset(node, 0, sizeof(PHP_VAR_NODE));
352 node->value.type = PHP_VAL_NONE;
353
354 return node;
355}
356
357PHP_VAR_NODE *make_array_var()
358{
359 PHP_VAR_NODE *node = make_var_node();
360 cast_value_array(&node->value);
361
362 return node;
363}
364
365/*
366 * Called from lexer when ${IDENT} is recognized
367 */
368PHP_EXP_NODE *get_var_node(const char *name)
369{
370 PHP_EXP_NODE *node = make_zero_exp_node();
371 node->op = PHP_OP_VAR;
372
373 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, name);
374 if ( si ) {
375 if ( (si->type == PHP_SCOPE_VAR) || (si->type == PHP_SCOPE_PARAM) ) {
376 node->var_si_node = si;
377 } else {
378 //
379 // Error: symbol already defined as different entity
380 //
381 php_report_error(PHP_ERROR,
382 "symbol [%s] already defined as different entity (%d)", name, si->type);
383 }
384 } else {
385 add_var_2_scope(g_current_scope, make_var_node(), name);
386 node->var_si_node = get_scope_item(g_current_scope, name);
387 }
388
389 return node;
390}
391
392void free_var_node(PHP_VAR_NODE *v)
393{
394 delete v;
395}
396
397/*
398 * Init function scope table before transferring control there.
399 * 1. Evaluate all by-value params
400 * 2. Lvalue-evaluate all by-ref params and adjust pointers
401 */
402void func_scope_init(PHP_FUNC_PARAM_DEF *params, int param_count,
403 PHP_SCOPE_TABLE_TYPE * /*scope_map*/, PHP_VALUE_NODE *arg_array,
404 std::map<std::string, PHP_VAR_NODE *> &saved_vars)
405{
406 //
407 // Step 1: save origival vars
408 PHP_SCOPE_TABLE_TYPE *curr_scope_map = (PHP_SCOPE_TABLE_TYPE *)g_current_scope;
409 for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();++i) {
410 if ( (i->second->type == PHP_SCOPE_VAR) || (i->second->type == PHP_SCOPE_PARAM) ) {
411 if ( !(i->second->var->flags & PHP_VARFLAG_STATIC0x0001) ) {
412 //printf("Saving %s = %p->%p\n", i->first.c_str(), i->second, i->second->var);
413 saved_vars[i->first] = i->second->var;
414 }
415 }
416 }
417 //
418 // Step 2: calculate new values of call parameters
419 PHP_VAR_NODE *call_params[PHP_MAX_FUNC_PARAM16];
420 for(int i = 0; i < param_count; i++) {
421 PHP_VAR_NODE *curr_arg_val = array_get_by_int_key(arg_array, i);
422 if ( curr_arg_val->value.type != PHP_VAL_NONE ) {
423 if ( (curr_arg_val->flags & PHP_VARFLAG_BYREF0x0004) || params[i].byref ) {
424 call_params[i] = php_expr_eval_lvalue((PHP_EXP_NODE *)curr_arg_val->value.ptr_val);
425 if ( !call_params[i] ) {
426 php_report_error(PHP_ERROR, "Byref parameter is not lvalue");
427 return;
428 }
429 } else {
430 call_params[i] = make_var_node();
431 call_params[i]->ref_count = 1;
432 //printf("alloc var for callparam %d -> %p\n", i, call_params[i]);
433 php_expr_eval((PHP_EXP_NODE *)curr_arg_val->value.ptr_val, &call_params[i]->value);
434 }
435 } else {
436 // put default value
437 php_report_error(PHP_WARNING, "Default parameters are not implemented yet");
438 call_params[i] = make_var_node();
439 call_params[i]->ref_count = 1;
440 }
441 }
442 //
443 // Step 3: assign new values to call parameters
444 for(int i = 0; i < param_count; i++) {
445 //printf("assign new param si=%p var=%p -> %p\n", params[i].si_var, params[i].si_var->var, call_params[i]);
446 params[i].si_var->var = call_params[i];
447 }
448
449 //
450 // Step 4: allocate new stack local vars
451 for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();++i) {
452 if ( !((i->second->type == PHP_SCOPE_PARAM) || (i->second->type == PHP_SCOPE_VAR)) ) {
453 continue;
454 }
455 //printf("in scope: %p %s [ %s ] with flags %02x\n", i->second, i->second->type == PHP_SCOPE_PARAM ? "param" : "var",
456 // i->first.c_str(), i->second->var->flags);
457 if ( !(i->second->var->flags & PHP_VARFLAG_STATIC0x0001) && (i->second->type != PHP_SCOPE_PARAM) ) {
458 //printf("alloc new for %s [ %p->%p ]\n", i->first.c_str(), i->second, i->second->var);
459 i->second->var = make_var_node();
460 i->second->var->ref_count = 1;
461 }
462 }
463}
464
465/*
466 * Since by-ref params changes pointers in scope table, we need to restore them
467 * to original objects, so:
468 * 1. Memory will not leak
469 * 2. Next call may be using same params by-value, so it need independent varnode
470 */
471static void func_scope_copy_back(PHP_FUNC_PARAM_DEF *params, int param_count,
472 PHP_SCOPE_TABLE_TYPE * /*scope_map*/, PHP_VALUE_NODE *arg_array,
473 std::map<std::string, PHP_VAR_NODE *> &saved_vars)
474{
475 /*
476 if ( param_count < array_get_size(arg_array) ) {
477 param_count = array_get_size(arg_array);
478 }
479 */
480 PHP_VAR_NODE *call_params[PHP_MAX_FUNC_PARAM16];
481 int call_param_2free_count = 0;
482 for(int i = 0; i < param_count; i++) {
483 PHP_VAR_NODE *curr_arg_val = array_get_by_int_key(arg_array, i);
484 if ( !((curr_arg_val->flags & PHP_VARFLAG_BYREF0x0004) || params[i].byref) ) {
485 //printf("Delete param %d %p->%p\n", i, params[i].si_var, params[i].si_var->var);
486 call_params[call_param_2free_count++] = params[i].si_var->var;
487 }
488 params[i].si_var->var = params[i].var;
489 }
490
491 PHP_SCOPE_TABLE_TYPE *curr_scope_map = (PHP_SCOPE_TABLE_TYPE *)g_current_scope;
492 for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();++i) {
493 if ( (i->second->type == PHP_SCOPE_VAR) || (i->second->type == PHP_SCOPE_PARAM) ) {
494 if ( !(i->second->var->flags & PHP_VARFLAG_STATIC0x0001) ) {
495 //printf("Restoring %s = %p->%p\n", i->first.c_str(), i->second, i->second->var);
496 //assert(saved_vars[i->first]);
497 if (i->second->type == PHP_SCOPE_VAR) {
498 value_value_free(&i->second->var->value);
499 delete i->second->var;
500 }
501 i->second->var = saved_vars[i->first];
502 }
503 }
504 }
505 for(int i = 0; i < call_param_2free_count; i++) {
506 value_value_free(&call_params[i]->value);
507 delete call_params[i];
508 }
509}
510
511PHP_SCOPE_TABLE make_scope_table()
512{
513 PHP_SCOPE_TABLE_TYPE *scope_map = new PHP_SCOPE_TABLE_TYPE;
514
515 return scope_map;
516}
517
518void switch_push_scope_table(PHP_SCOPE_TABLE new_table)
519{
520 PHP_SCOPE_STACK_TYPE *scope_stack = (PHP_SCOPE_STACK_TYPE *)g_scope_stack;
521 scope_stack->push_back((PHP_SCOPE_TABLE_TYPE *)g_current_scope);
522 g_current_scope = new_table;
523}
524
525void switch_pop_scope_table(int old_free)
526{
527 PHP_SCOPE_STACK_TYPE *scope_stack = (PHP_SCOPE_STACK_TYPE *)g_scope_stack;
528 if ( old_free ) {
529 delete_scope_table(g_current_scope);
530 }
531 if ( scope_stack->size() == 0 ) {
532 php_report_error(PHP_INTERNAL_ERROR, "Stack underrun - no valid scope");
533 }
534 g_current_scope = scope_stack->back();
535 scope_stack->pop_back();
536}
537
538void delete_scope_table(PHP_SCOPE_TABLE scope)
539{
540 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
541
542 for(PHP_SCOPE_TABLE_TYPE::iterator i = scope_map->begin(); i != scope_map->end();++i) {
543 switch ( i->second->type ) {
544 case PHP_SCOPE_PARAM:
545 //break;
546 case PHP_SCOPE_VAR: {
547 //printf("removing %s\n", i->first.c_str());
548 PHP_VAR_NODE *var = i->second->var;
549 var_node_free(var);
550 }
551 break;
552 case PHP_SCOPE_FUNC: {
553 PHP_SYN_NODE *func = i->second->func;
554 php_syn_tree_free(func);
555 }
556 break;
557 case PHP_SCOPE_CLASS: {
558 PHP_SYN_NODE *class_decl = i->second->class_decl;
559 php_syn_tree_free(class_decl);
560 }
561 break;
562 case PHP_SCOPE_NONE:
563 php_report_error(PHP_INTERNAL_ERROR, "Scope table can not have such items");
564 break;
565 }
566 delete i->second;
567 }
568 delete scope_map;
569}
570
571void add_func_2_scope(PHP_SCOPE_TABLE scope, PHP_SYN_NODE *func)
572{
573 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
574 std::string key(func->func_decl->name);
575 if ( scope_map->count(key) ) {
576 // error - function already defined
577 php_report_error(PHP_ERROR, "Can not add function to scope table - already present");
578 } else {
579 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
580 it->type = PHP_SCOPE_FUNC;
581 it->func = func;
582 (*scope_map)[key] = it;
583 }
584}
585
586void add_class_2_scope(PHP_SCOPE_TABLE scope, PHP_SYN_NODE *class_node)
587{
588 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
589 std::string key(class_node->class_decl->name);
590 if ( scope_map->count(key) ) {
591 // error - function already defined
592 php_report_error(PHP_ERROR, "Can not add function to scope table - already present");
593 } else {
594 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
595 it->type = PHP_SCOPE_CLASS;
596 it->class_decl = class_node;
597 (*scope_map)[key] = it;
598 }
599}
600
601static PHP_SCOPE_ITEM *make_named_scope_item(PHP_SCOPE_TABLE scope, const char *name)
602{
603 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
604 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
605 memset(it, 0, sizeof(PHP_SCOPE_ITEM));
606
607 std::string key(name);
608 (*scope_map)[key] = it;
609 return it;
610}
611
612PHP_SCOPE_ITEM *add_var_2_scope(PHP_SCOPE_TABLE scope, PHP_VAR_NODE *var, const char *name)
613{
614 PHP_SCOPE_ITEM *it = make_named_scope_item(scope, name);
615 it->type = PHP_SCOPE_VAR;
616 it->var = var;
617 var->ref_count++;
618 return it;
619}
620
621PHP_SCOPE_ITEM_TYPE get_scope_item_type(PHP_SCOPE_TABLE scope, const char *name)
622{
623 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
624 std::string key(name);
625 if ( scope_map->count(key) ) {
626 PHP_SCOPE_ITEM *it = (*scope_map)[key];
627 return it->type;
628 }
629 return PHP_SCOPE_NONE;
630}
631
632PHP_SCOPE_ITEM *get_scope_item(PHP_SCOPE_TABLE scope, const char *name)
633{
634 assert(name)(static_cast <bool> (name) ? void (0) : __assert_fail (
"name", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
635 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
636 std::string key(name);
637 if ( scope_map->count(key) ) {
638 PHP_SCOPE_ITEM *it = (*scope_map)[key];
639 return it;
640 }
641 return 0;
642}
643
644const char *get_scope_var_name(PHP_SCOPE_TABLE scope, PHP_VAR_NODE *var)
645{
646 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
647
648 for(PHP_SCOPE_TABLE_TYPE::iterator i = scope_map->begin(); i != scope_map->end();++i) {
649 if ( i->second->type == PHP_SCOPE_VAR ) {
650 PHP_VAR_NODE *curr_var = i->second->var;
651 if ( curr_var == var ) {
652 return i->first.c_str();
653 }
654 }
655 }
656 return 0;
657}
658
659
660/* array operations */
661const std::string &array_get_ith_key(PHP_VALUE_NODE *array, int i)
662{
663 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
664 PHP_ARRAY_ITER_TYPE it = arr_ptr->array.begin();
665 while(i--) ++it;
666 return it->first;
667}
668
669
670PHP_VAR_NODE *array_get_by_str_key(PHP_VALUE_NODE *array, const std::string &key)
671{
672 if ( array->type != PHP_VAL_ARRAY ) {
673 return 0;
674 }
675 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
676 if ( arr_ptr->array.count(key) ) {
677 return (arr_ptr->array)[key];
678 } else {
679 PHP_VAR_NODE *add_node = make_var_node();
680 add_node->value.type = PHP_VAL_NONE;
681 add_node->ref_count++;
682 (arr_ptr->array)[key] = add_node;
683 arr_ptr->sorted_keys.push_back(key);
684 return add_node;
685 }
686}
687
688PHP_VAR_NODE *array_get_by_int_key(PHP_VALUE_NODE *array, int key)
689{
690 if ( array->type != PHP_VAL_ARRAY ) {
691 return 0;
692 }
693 char s_key[32];
694 snprintf(s_key, sizeof(s_key), "%d", key);
695 return array_get_by_str_key(array, s_key);
696}
697
698PHP_VAR_NODE *array_get_by_key(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key)
699{
700 if ( array->type != PHP_VAL_ARRAY ) {
701 return 0;
702 }
703 PHP_VALUE_NODE s_key = *key;
704 cast_value_str(&s_key);
705 return array_get_by_str_key(array, s_key.str_val);
706}
707
708void array_set_by_key(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key, PHP_VAR_NODE *node)
709{
710 if ( array->type != PHP_VAL_ARRAY ) {
711 return;
712 }
713 PHP_VALUE_NODE s_key = *key;
714 cast_value_str(&s_key);
715 array_remove_at_str_key(array, s_key.str_val);
716 array_add_to_str_key(array, s_key.str_val, node);
717 value_value_free(&s_key);
718}
719
720void array_add_to_str_key(PHP_VALUE_NODE *array, const std::string &key, PHP_VAR_NODE *node)
721{
722 if ( array->type != PHP_VAL_ARRAY ) {
723 return ;
724 }
725 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
726 if ( !arr_ptr->array.count(key) ) {
727 node->ref_count++;
728 (arr_ptr->array)[key] = node;
729 arr_ptr->sorted_keys.push_back(key);
730 }
731}
732
733void array_remove_at_str_key(PHP_VALUE_NODE *array, const std::string &key)
734{
735 if ( array->type != PHP_VAL_ARRAY ) {
736 return ;
737 }
738 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
739 if ( arr_ptr->array.count(key) ) {
740 PHP_VAR_NODE *node = (arr_ptr->array)[key];
741 var_node_free(node);
742 arr_ptr->array.erase(key);
743 for(PHP_ARRAY_KEY_ITER_TYPE i = arr_ptr->sorted_keys.begin(); i != arr_ptr->sorted_keys.end(); ++i) {
744 if ( *i == key ) {
745 arr_ptr->sorted_keys.erase(i);
746 break;
747 }
748 }
749 }
750}
751
752void array_add_to_int_key(PHP_VALUE_NODE *array, int key, PHP_VAR_NODE *node)
753{
754 char s_key[32];
755 snprintf(s_key, sizeof(s_key), "%d", key);
756 array_add_to_str_key(array, s_key, node);
757}
758
759
760int array_is_key_here(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key)
761{
762 if ( array->type != PHP_VAL_ARRAY ) {
763 return 0;
764 }
765 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
766 PHP_VALUE_NODE s_key = *key;
767 cast_value_str(&s_key);
768 std::string arr_key(s_key.str_val);
769
770 return arr_ptr->array.count(arr_key);
771}
772
773int array_get_size(PHP_VALUE_NODE *array)
774{
775 if ( array->type != PHP_VAL_ARRAY ) {
776 return 0;
777 }
778 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
779
780 return arr_ptr->array.size();
781}
782
783PHP_VAR_NODE *array_push_back(PHP_VALUE_NODE *array)
784{
785 for(int i = 0; i < 0xffff;i++) {
786 PHP_VAR_NODE *arr_var_node = array_get_by_int_key(array, i);
787 if ( arr_var_node->value.type == PHP_VAL_NONE ) {
788 return arr_var_node;
789 }
790 }
791 // array size reached 64K ?!
792 return 0;
793}
794
795/* value manipulation - assignment and disposal */
796
797void value_value_assign(PHP_VALUE_NODE *dst, PHP_VALUE_NODE *src)
798{
799 // first, free old value
800 value_value_free(dst);
801 dst->type = src->type;
802 switch(src->type) {
803 // scalars are copied. Objects are copied too, since
804 // interpreter doesn't allocate them.
805 case PHP_VAL_NONE:
806 case PHP_VAL_BOOL:
807 case PHP_VAL_INT:
808 case PHP_VAL_FLOAT:
809 case PHP_VAL_OBJECT:
810 // assign biggest in union
811 dst->obj_val = src->obj_val;
812 break;
813 // string is duplicated
814 case PHP_VAL_STRING: {
815 dst->str_val = strdup(src->str_val);
816 break;
817 }
818 // array must duplicate all it's values
819 case PHP_VAL_ARRAY: {
820 dst->ptr_val = new PHP_ARRAY_TYPE;
821 PHP_ARRAY_TYPE *src_array = (PHP_ARRAY_TYPE *)src->ptr_val;
822 for(PHP_ARRAY_KEY_ITER_TYPE i = src_array->sorted_keys.begin(); i != src_array->sorted_keys.end(); ++i) {
823 PHP_VAR_NODE *added = array_get_by_str_key(dst, *i);
824 value_value_assign(&added->value, &src_array->array[*i]->value);
825 }
826 break;
827 }
828
829 case PHP_VAL_VAR_NODE:
830 case PHP_VAL_INT_DATA: break;
831 }
832}
833
834void var_node_free(PHP_VAR_NODE *var)
835{
836 assert(var && var->ref_count)(static_cast <bool> (var && var->ref_count) ?
void (0) : __assert_fail ("var && var->ref_count"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
837 var->ref_count--;
838 if ( var->ref_count == 0 ) {
839 value_value_free(&var->value);
840 delete var;
841 }
842}
843
844void value_value_free(PHP_VALUE_NODE *val)
845{
846 switch(val->type) {
847 case PHP_VAL_NONE:
848 case PHP_VAL_BOOL:
849 case PHP_VAL_INT:
850 case PHP_VAL_FLOAT:
851 break;
852 case PHP_VAL_STRING: {
853 free(val->str_val);
854 val->str_val = 0;
855 break;
856 }
857 case PHP_VAL_ARRAY: {
858 for(PHP_ARRAY_ITER_TYPE i = ((PHP_ARRAY_TYPE *)val->ptr_val)->array.begin();
859 i != ((PHP_ARRAY_TYPE *)val->ptr_val)->array.end(); ++i) {
860 PHP_VAR_NODE *var_i = i->second;
861 var_node_free(var_i);
862 }
863 delete ((PHP_ARRAY_TYPE *)val->ptr_val);
864 break;
865 }
866 case PHP_VAL_OBJECT: break;
867
868 case PHP_VAL_VAR_NODE:
869 case PHP_VAL_INT_DATA: break;
870 }
871 val->type = PHP_VAL_NONE;
872}
873
874/* casting functions */
875void cast_value_dnum(PHP_VALUE_NODE *val)
876{
877 switch(val->type) {
878 case PHP_VAL_NONE: val->int_val = 0; break;
879 case PHP_VAL_BOOL:
880 case PHP_VAL_INT: break;
881 case PHP_VAL_FLOAT: val->int_val = (int)val->float_val; break;
882 case PHP_VAL_STRING: {
883 char *str = val->str_val;
884 val->int_val = atoll(val->str_val);
885 free(str);
886 break;
887 }
888 case PHP_VAL_ARRAY:
889 case PHP_VAL_OBJECT: val->int_val = 0; break;
890 case PHP_VAL_VAR_NODE:
891 case PHP_VAL_INT_DATA: assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
; break;
892 }
893 val->type = PHP_VAL_INT;
894}
895
896void cast_value_bool(PHP_VALUE_NODE *val)
897{
898 cast_value_dnum(val);
899 val->type = PHP_VAL_BOOL;
900}
901
902void cast_value_fnum(PHP_VALUE_NODE *val)
903{
904 switch(val->type) {
905 case PHP_VAL_NONE: val->float_val = 0; break;
906 case PHP_VAL_BOOL:
907 case PHP_VAL_INT: val->float_val = val->int_val; break;
908 case PHP_VAL_FLOAT: break;
909 case PHP_VAL_STRING: {
910 char *str = val->str_val;
911 val->float_val = atof(val->str_val);
912 free(str);
913 break;
914 }
915 case PHP_VAL_ARRAY:
916 case PHP_VAL_OBJECT: val->float_val = 0; break;
917 case PHP_VAL_VAR_NODE:
918 case PHP_VAL_INT_DATA: assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
; break;
919 }
920 val->type = PHP_VAL_FLOAT;
921}
922
923void cast_value_str(PHP_VALUE_NODE *val)
924{
925 char buff[256];
926 switch(val->type) {
927 case PHP_VAL_NONE: buff[0] = 0; break;
928 case PHP_VAL_BOOL:
929 case PHP_VAL_INT: snprintf(buff, sizeof(buff), "%" PRIu64"l" "u", val->int_val); break;
930 case PHP_VAL_FLOAT: snprintf(buff, sizeof(buff), "%.02f", val->float_val); break;
931 case PHP_VAL_STRING: return;
932 case PHP_VAL_ARRAY: {
933 delete ((PHP_ARRAY_TYPE *)val->ptr_val);
934 strcpy(buff, "Array"); break;
935 }
936 case PHP_VAL_OBJECT: strcpy(buff, "Object"); break;
937 case PHP_VAL_VAR_NODE:
938 case PHP_VAL_INT_DATA: assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
; break;
939 }
940 val->str_val = strdup(buff);
941 val->type = PHP_VAL_STRING;
942}
943
944void cast_value_array(PHP_VALUE_NODE *val)
945{
946 switch(val->type) {
947 case PHP_VAL_NONE:
948 case PHP_VAL_BOOL:
949 case PHP_VAL_INT:
950 case PHP_VAL_FLOAT: break;
951 case PHP_VAL_STRING: free(val->str_val);
952 case PHP_VAL_ARRAY: return;
953 case PHP_VAL_OBJECT: ;/* must call to free_obj() */
954 case PHP_VAL_VAR_NODE:
955 case PHP_VAL_INT_DATA: assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
; break;
956 }
957 val->ptr_val = new PHP_ARRAY_TYPE;
958 val->type = PHP_VAL_ARRAY;
959}
960
961/*
962 * Function calls
963 */
964PHP_EXP_NODE *make_func_call_exp(char *func_name, PHP_EXP_NODE *args)
965{
966 PHP_EXP_NODE *call_node = make_zero_exp_node();
967
968 call_node->op = PHP_OP_FUNC_CALL;
969 // copy function name
970 call_node->tree_node.left = make_zero_exp_node();
971 call_node->tree_node.left->op = PHP_OP_VAL;
972 call_node->tree_node.left->val_node.type = PHP_VAL_STRING;
973 call_node->tree_node.left->val_node.str_val = strdup(func_name);
974 // set params
975 call_node->tree_node.right = args;
976
977 return call_node;
978}
979
980PHP_EXP_NODE *make_func_call_param_list()
981{
982 PHP_VAR_NODE *params = make_array_var();
983
984 PHP_EXP_NODE *exp_node = make_zero_exp_node();
985
986 exp_node->op = PHP_OP_VAR;
987 exp_node->var_node = params;
988
989 return exp_node;
990}
991
992void func_call_add_expr(PHP_VAR_NODE *paramlist, PHP_EXP_NODE *arg, int byref)
993{
994 PHP_VAR_NODE *node = array_push_back(&paramlist->value);
995 node->value.type = PHP_VAL_INT_DATA;
996 node->value.ptr_val = arg;
997 if ( byref ) {
998 node->flags |= PHP_VARFLAG_BYREF0x0004;
999 }
1000}
1001
1002void php_add_native_func(PHP_BLTIN_FUNC_DEF *def)
1003{
1004 if ( get_scope_item_type(g_global_scope, def->name) != PHP_SCOPE_NONE ) {
1
Taking false branch
1005 //
1006 // Error: something already defined by this name
1007 //
1008 php_report_error(PHP_ERROR, "Can't add scope item: symbol already defined");
1009 return;
1010 }
1011 PHP_SCOPE_TABLE func_scope = make_scope_table();
1012
1013 PHP_SYN_NODE *decl_node = make_func_decl_syn_node(def->name, 0);
2
Calling 'make_func_decl_syn_node'
5
Returned allocated memory
1014 decl_node->func_decl->param_count = def->param_count;
1015 decl_node->func_decl->params = new PHP_FUNC_PARAM_DEF[def->param_count];
1016
1017 //
1018 // Built-in functions don't have class specifier, and can handle
1019 // default arguments internally
1020 //
1021 memset(decl_node->func_decl->params, 0, sizeof(PHP_FUNC_PARAM_DEF) * def->param_count);
1022 for(int i = 0; i < def->param_count;i++) {
6
Assuming 'i' is >= field 'param_count'
7
Loop condition is false. Execution continues on line 1032
1023 PHP_VAR_NODE *func_param = make_var_node();
1024 char param_name[32];
1025 snprintf(param_name, sizeof(param_name), "__param_%d", i);
1026
1027 decl_node->func_decl->params[i].def_value.type = PHP_VAL_NONE;
1028 decl_node->func_decl->params[i].var = func_param;
1029 decl_node->func_decl->params[i].si_var = add_var_2_scope(func_scope, func_param, param_name);
1030 decl_node->func_decl->params[i].si_var->type = PHP_SCOPE_PARAM;
1031 }
1032 decl_node->func_decl->scope = func_scope;
1033 decl_node->func_decl->is_native = 1;
1034 decl_node->func_decl->native_ptr = def->func;
1035
1036 add_func_2_scope(g_global_scope, decl_node);
1037}
8
Potential leak of memory pointed to by 'decl_node'
1038
1039void php_add_native_class(const char *name, PHP_NATIVE_PROP_GET_FUNC_PTR prop_get_native_ptr)
1040{
1041 if ( get_scope_item_type(g_global_scope, name) != PHP_SCOPE_NONE ) {
1042 //
1043 // Error: something already defined by this name
1044 //
1045 php_report_error(PHP_ERROR, "Can't add scope item: symbol already defined");
1046 return;
1047 }
1048 PHP_SYN_NODE *decl_node = make_class_decl_syn_node();
1049 decl_node->class_decl->name = strdup(name);
1050 decl_node->class_decl->is_native = 1;
1051 decl_node->class_decl->native_prop_get_ptr = prop_get_native_ptr;
1052 add_class_2_scope(g_global_scope, decl_node);
1053}
1054
1055void php_engine_init()
1056{
1057 g_global_scope = make_scope_table();
1058
1059 g_current_scope = g_global_scope;
1060
1061 g_scope_stack = new PHP_SCOPE_STACK_TYPE;
1062
1063 // here built-in functions/objects/vars are loaded
1064 php_init_core_lib();
1065 php_init_amule_lib();
1066}
1067
1068void php_exp_tree_free(PHP_EXP_NODE *tree)
1069{
1070 if ( !tree ) {
1071 return;
1072 }
1073 switch ( tree->op ) {
1074 case PHP_OP_VAR:
1075 /* will be deleted during scope table destruction */
1076 break;
1077 case PHP_OP_VAL:
1078 value_value_free(&tree->val_node);
1079 break;
1080 case PHP_OP_FUNC_CALL: {
1081 php_exp_tree_free(tree->tree_node.left);
1082 PHP_VAR_NODE *args = tree->tree_node.right->var_node;
1083 PHP_VALUE_NODE *args_array = &args->value;
1084 for(PHP_ARRAY_ITER_TYPE i = ((PHP_ARRAY_TYPE *)args_array->ptr_val)->array.begin();
1085 i != ((PHP_ARRAY_TYPE *)args_array->ptr_val)->array.end(); ++i) {
1086 PHP_VAR_NODE *var_i = i->second;
1087 php_exp_tree_free((PHP_EXP_NODE *)var_i->value.ptr_val);
1088 }
1089 value_value_free(&args->value);
1090 delete tree->tree_node.right->var_node;
1091 delete tree->tree_node.right;
1092 }
1093 break;
1094 case PHP_OP_ARRAY: {
1095 PHP_EXP_NODE *curr = tree->tree_node.left;
1096 while (curr) {
1097 PHP_EXP_NODE *next = curr->next;
1098 php_exp_tree_free(curr->exp_node);
1099 delete curr;
1100 curr = next;
1101 }
1102 }
1103 break;
1104 case PHP_OP_MUX:
1105 php_exp_tree_free(tree->exp_node);
1106 /* fall through */
1107 default:
1108 // all other things using left/right
1109 php_exp_tree_free(tree->tree_node.left);
1110 php_exp_tree_free(tree->tree_node.right);
1111 }
1112
1113 delete tree;
1114}
1115
1116void php_syn_tree_free(PHP_SYN_NODE *tree)
1117{
1118 while ( tree ) {
1119 switch ( tree->type ) {
1120 case PHP_ST_EXPR:
1121 case PHP_ST_RET:
1122 php_exp_tree_free(tree->node_expr);
1123 break;
1124 case PHP_ST_ECHO: {
1125 PHP_EXP_NODE *curr = tree->node_expr;
1126 while (curr) {
1127 PHP_EXP_NODE *next = curr->next;
1128 php_exp_tree_free(curr->exp_node);
1129 delete curr;
1130 curr = next;
1131 }
1132 }
1133 break;
1134 case PHP_ST_IF:
1135 php_exp_tree_free(tree->node_if.cond);
1136 php_syn_tree_free(tree->node_if.code_if);
1137 php_syn_tree_free(tree->node_if.code_else);
1138 break;
1139 case PHP_ST_WHILE:
1140 case PHP_ST_DO_WHILE:
1141 php_exp_tree_free(tree->node_while.cond);
1142 php_syn_tree_free(tree->node_while.code);
1143 break;
1144 case PHP_ST_FOR:
1145 php_exp_tree_free(tree->node_for.do_start);
1146 php_exp_tree_free(tree->node_for.cond);
1147 php_exp_tree_free(tree->node_for.do_next);
1148 php_syn_tree_free(tree->node_for.code);
1149 break;
1150 case PHP_ST_FOREACH:
1151 php_exp_tree_free(tree->node_foreach.elems);
1152 php_syn_tree_free(tree->node_foreach.code);
1153 break;
1154 case PHP_ST_CONTINUE:
1155 case PHP_ST_BREAK:
1156 break;
1157 case PHP_ST_FUNC_DECL:
1158 if ( !tree->func_decl->is_native ) {
1159 php_syn_tree_free(tree->func_decl->code);
1160 }
1161 delete_scope_table(tree->func_decl->scope);
1162 free(tree->func_decl->name);
1163 for(int i = 0; i < tree->func_decl->param_count; i++) {
1164 if (tree->func_decl->params[i].class_name) {
1165 free(tree->func_decl->params[i].class_name);
1166 }
1167 }
1168 delete [] tree->func_decl->params;
1169 delete tree->func_decl;
1170 break;
1171 case PHP_ST_SWITCH: {
1172 php_exp_tree_free(tree->node_switch.cond);
1173 php_syn_tree_free(tree->node_switch.case_list->exp_node->tree_node.syn_right);
1174 PHP_EXP_NODE *curr = tree->node_switch.case_list;
1175 while (curr) {
1176 PHP_EXP_NODE *next = curr->next;
1177 if ( curr->exp_node ) {
1178 php_exp_tree_free(curr->exp_node->tree_node.left);
1179 delete curr->exp_node;
1180 }
1181 delete curr;
1182 curr = next;
1183 }
1184 }
1185 break;
1186 case PHP_ST_CLASS_DECL:
1187 free(tree->class_decl->name);
1188 delete tree->class_decl;
1189 break;
1190 }
1191 PHP_SYN_NODE *next_node = tree->next_node;
1192 delete tree;
1193 tree = next_node;
1194 }
1195}
1196
1197void php_engine_free()
1198{
1199 if ( g_global_scope ) {
1200 delete_scope_table(g_global_scope);
1201 }
1202 php_syn_tree_free(g_syn_tree_top);
1203 g_global_scope = 0;
1204 g_current_scope = 0;
1205 delete (PHP_SCOPE_STACK_TYPE *)g_scope_stack;
1206}
1207
1208/*
1209 * Create reference. This is recoursive process, since operators []
1210 * can be stacked: $a[1][2][3] = & $b;
1211 * There's 3 valid cases in making reference:
1212 * 1,2. Target is scalar variable or variable by name ${xxx}
1213 * 3. Target is member of array.
1214 */
1215static void exp_set_ref(PHP_EXP_NODE *expr, PHP_VAR_NODE *var, PHP_VALUE_NODE *key)
1216{
1217 switch ( expr->op ) {
1218 case PHP_OP_VAR: {
1219 if ( expr->var_si_node->var != var ) {
1220 if ( key ) {
1221 cast_value_array(&expr->var_si_node->var->value);
1222 array_set_by_key(&expr->var_si_node->var->value, key, var);
1223 } else {
1224 var_node_free(expr->var_si_node->var);
1225 expr->var_si_node->var = var;
1226 var->ref_count++;
1227 }
1228 }
1229 }
1230 break;
1231 case PHP_OP_ARRAY_BY_KEY: {
1232 PHP_VALUE_NODE i_key;
1233 i_key.type = PHP_VAL_NONE;
1234 php_expr_eval(expr->tree_node.right, &i_key);
1235 exp_set_ref(expr->tree_node.left, var, &i_key);
1236 }
1237 break;
1238 default:
1239 php_report_error(PHP_ERROR, "Bad left part of operator =&: (%d)",
1240 expr->tree_node.left->op);
1241 }
1242}
1243
1244/*
1245 * This is heart of expression tree: evaluation. It's split into 2 functions
1246 * where 1 evaluates "value" of expression, and other evaluates "lvalue" i.e. assignable
1247 * entity from given subtree.
1248 */
1249
1250void php_expr_eval(PHP_EXP_NODE *expr, PHP_VALUE_NODE *result)
1251{
1252 PHP_VALUE_NODE result_val_right, result_val_left;
1253 PHP_VAR_NODE *lval_node = 0;
1254 PHP_SCOPE_ITEM *si = 0;
1255 result_val_right.type = PHP_VAL_NONE;
1256 result_val_left.type = PHP_VAL_NONE;
1257 switch(expr->op) {
1258 case PHP_OP_VAL:
1259 if ( result ) {
1260 value_value_assign(result, &expr->val_node);
1261 }
1262 break;
1263 case PHP_OP_VAR:
1264 if ( result ) {
1265 value_value_assign(result, &expr->var_si_node->var->value);
1266 }
1267 break;
1268 case PHP_OP_ASS:
1269 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1270 if ( !lval_node ) {
1271 break;
1272 }
1273 php_expr_eval(expr->tree_node.right, &lval_node->value);
1274 if ( result ) {
1275 value_value_assign(result, &lval_node->value);
1276 }
1277 break;
1278 case PHP_OP_ARRAY_BY_KEY:
1279 php_expr_eval(expr->tree_node.right, &result_val_right);
1280 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1281 cast_value_array(&lval_node->value);
1282 cast_value_str(&result_val_right);
1283 lval_node = array_get_by_key(&lval_node->value, &result_val_right);
1284 if ( result ) {
1285 value_value_assign(result, &lval_node->value);
1286 }
1287 break;
1288 case PHP_MAKE_REF:
1289 lval_node = php_expr_eval_lvalue(expr->tree_node.right);
1290 if ( !lval_node ) {
1291 break;
1292 }
1293 exp_set_ref(expr->tree_node.left, lval_node, 0);
1294 break;
1295 case PHP_OP_ARRAY:
1296 if ( result ) {
1297 PHP_EXP_NODE *curr = expr->tree_node.left;
1298 value_value_free(result);
1299 cast_value_array(result);
1300 while ( curr ) {
1301 switch( curr->exp_node->op ) {
1302 case PHP_OP_ARRAY_PAIR:
1303 if ( curr->exp_node->tree_node.right ) {
1304 php_expr_eval(curr->exp_node->tree_node.left, &result_val_left);
1305 cast_value_str(&result_val_left);
1306 lval_node = array_get_by_key(result, &result_val_left);
1307 value_value_free(&result_val_left);
1308 php_expr_eval(curr->exp_node->tree_node.right, &lval_node->value);
1309 } else {
1310 lval_node = array_push_back(result);
1311 php_expr_eval(curr->exp_node->tree_node.left, &lval_node->value);
1312 }
1313 break;
1314 case PHP_OP_ARRAY_REF_PAIR:
1315 lval_node = php_expr_eval_lvalue(curr->exp_node->tree_node.right);
1316 break;
1317 default:
1318 php_report_error(PHP_INTERNAL_ERROR, "Array list contain wrong node");
1319 return;
1320 }
1321 curr = curr->next;
1322 }
1323 }
1324 break;
1325 case PHP_OP_FUNC_CALL:
1326 php_run_func_call(expr, result);
1327 break;
1328 case PHP_OP_LIST: {
1329 PHP_EXP_NODE *curr = expr;
1330 while ( curr ) {
1331 if ( curr->exp_node ) {
1332 php_expr_eval(curr->exp_node, result);
1333 }
1334 curr = curr->next;
1335 }
1336 }
1337 break;
1338 case PHP_OP_CAT:
1339 php_expr_eval(expr->tree_node.right, &result_val_right);
1340 php_expr_eval(expr->tree_node.left, &result_val_left);
1341 if ( result ) {
1342 cast_value_str(&result_val_left);
1343 cast_value_str(&result_val_right);
1344 value_value_free(result);
1345 result->type = PHP_VAL_STRING;
1346 // using "malloc" and not "new" since all strings are freed
1347 // later with "free" and not "delete"
1348 result->str_val = (char *)malloc(strlen(result_val_left.str_val) +
1349 strlen(result_val_right.str_val) + 1);
1350 strcpy(result->str_val, result_val_left.str_val);
1351 strcat(result->str_val, result_val_right.str_val);
1352 }
1353 break;
1354 case PHP_OP_MUX:
1355 php_expr_eval(expr->exp_node, &result_val_right);
1356 cast_value_bool(&result_val_right);
1357 if ( result_val_right.int_val ) {
1358 php_expr_eval(expr->tree_node.left, result);
1359 } else {
1360 php_expr_eval(expr->tree_node.right, result);
1361 }
1362 break;
1363 case PHP_OP_CAST_INT:
1364 if ( result ) {
1365 php_expr_eval(expr->tree_node.left, result);
1366 cast_value_dnum(result);
1367 }
1368 break;
1369 case PHP_OP_CAST_FLOAT:
1370 if ( result ) {
1371 php_expr_eval(expr->tree_node.left, result);
1372 cast_value_fnum(result);
1373 }
1374 break;
1375 case PHP_OP_CAST_BOOL:
1376 if ( result ) {
1377 php_expr_eval(expr->tree_node.left, result);
1378 cast_value_bool(result);
1379 }
1380 break;
1381 case PHP_OP_CAST_STR:
1382 if ( result ) {
1383 php_expr_eval(expr->tree_node.left, result);
1384 cast_value_str(result);
1385 }
1386 break;
1387 case PHP_OP_LOG_NOT:
1388 if ( result ) {
1389 php_expr_eval(expr->tree_node.left, &result_val_right);
1390 cast_value_bool(&result_val_right);
1391 result_val_right.int_val = !result_val_right.int_val;
1392 value_value_assign(result, &result_val_right);
1393 }
1394 break;
1395 case PHP_OP_NOT:
1396 if ( result ) {
1397 php_expr_eval(expr->tree_node.left, &result_val_right);
1398 cast_value_bool(&result_val_right);
1399 result_val_right.int_val = ~result_val_right.int_val;
1400 value_value_assign(result, &result_val_right);
1401 }
1402 break;
1403 case PHP_OP_ADD:
1404 case PHP_OP_SUB:
1405 case PHP_OP_MUL:
1406 case PHP_OP_DIV:
1407 php_expr_eval(expr->tree_node.right, &result_val_right);
1408 php_expr_eval(expr->tree_node.left, &result_val_left);
1409 if ( result ) {
1410 php_eval_simple_math(expr->op, &result_val_left, &result_val_right, result);
1411 }
1412 break;
1413 case PHP_OP_SHL:
1414 case PHP_OP_SHR:
1415 case PHP_OP_OR:
1416 case PHP_OP_AND:
1417 case PHP_OP_XOR:
1418 case PHP_OP_LOG_OR:
1419 case PHP_OP_LOG_AND:
1420 case PHP_OP_LOG_XOR:
1421 php_expr_eval(expr->tree_node.right, &result_val_right);
1422 php_expr_eval(expr->tree_node.left, &result_val_left);
1423 if ( result ) {
1424 php_eval_int_math(expr->op, &result_val_left, &result_val_right, result);
1425 }
1426 break;
1427 case PHP_OP_EQ:
1428 case PHP_OP_NEQ:
1429 case PHP_OP_GRT:
1430 case PHP_OP_LWR:
1431 php_expr_eval(expr->tree_node.right, &result_val_right);
1432 php_expr_eval(expr->tree_node.left, &result_val_left);
1433 if ( result ) {
1434 php_eval_compare(expr->op, &result_val_left, &result_val_right, result);
1435 }
1436 break;
1437 case PHP_OP_PRINT:
1438 php_expr_eval(expr->tree_node.left, &result_val_right);
1439 cast_value_str(&result_val_right);
1440 //
1441 // I print to buffer
1442 CPhPLibContext::Print(result_val_right.str_val);
1443 break;
1444 case PHP_OP_OBJECT_DEREF: // $x->y
1445 // take variable from scope of current object
1446 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1447 if ( !lval_node ) {
1448 php_report_error(PHP_ERROR, "Left part of -> must be lvalue");
1449 return;
1450 }
1451 if ( lval_node->value.type != PHP_VAL_OBJECT ) {
1452 php_report_error(PHP_ERROR, "Left part of -> must be an object");
1453 return;
1454 }
1455 if ( get_scope_item_type(g_global_scope, lval_node->value.obj_val.class_name) == PHP_SCOPE_NONE ) {
1456 php_report_error(PHP_ERROR, "Undeclared object");
1457 return;
1458 }
1459 si = get_scope_item(g_global_scope, lval_node->value.obj_val.class_name);
1460 if ( si->type != PHP_SCOPE_CLASS ) {
1461 php_report_error(PHP_INTERNAL_ERROR, "Object classname is not name of class");
1462 return;
1463 }
1464 // left part is ok, let's check the right
1465 if ( (expr->tree_node.right->op != PHP_OP_VAL) || (expr->tree_node.right->val_node.type != PHP_VAL_STRING) ) {
1466 php_report_error(PHP_ERROR, "Right part of -> must be string value");
1467 return;
1468 }
1469 if ( si->class_decl->class_decl->is_native ) {
1470 si->class_decl->class_decl->native_prop_get_ptr(lval_node->value.obj_val.inst_ptr,
1471 expr->tree_node.right->val_node.str_val, result);
1472 } else {
1473 php_report_error(PHP_ERROR, "Only native classes supported");
1474 return;
1475 }
1476 break;
1477 case PHP_OP_CLASS_DEREF: // A::y
1478 // take variable (static) from scope of current class
1479 php_report_error(PHP_ERROR, "Value of static class members not supported");
1480 break;
1481 default: ;
1482
1483 }
1484 value_value_free(&result_val_left);
1485 value_value_free(&result_val_right);
1486}
1487
1488PHP_VAR_NODE *php_expr_eval_lvalue(PHP_EXP_NODE *expr)
1489{
1490 PHP_VAR_NODE *lval_node = 0;
1491
1492 PHP_VALUE_NODE index;
1493 index.type = PHP_VAL_NONE;
1494
1495 switch(expr->op) {
1496 case PHP_OP_VAR:
1497 lval_node = expr->var_si_node->var;
1498 break;
1499 case PHP_OP_ARRAY_BY_KEY:
1500 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1501 if ( !lval_node ) {
1502 break;
1503 }
1504
1505 cast_value_array(&lval_node->value);
1506 if ( expr->tree_node.right ) {
1507 php_expr_eval(expr->tree_node.right, &index);
1508 if ( index.type == PHP_VAL_NONE ) {
1509 // something got wrong: evaluation result is not a value
1510 return 0;
1511 }
1512 cast_value_str(&index);
1513 lval_node = array_get_by_key(&lval_node->value, &index);
1514 value_value_free(&index);
1515 } else {
1516 // this is "$xxx[] = " construct.
1517 lval_node = array_push_back(&lval_node->value);
1518 }
1519 case PHP_OP_VAR_BY_EXP: // ${"xxx"}
1520 // should take variable from current scope
1521 break;
1522 case PHP_OP_OBJECT_DEREF: // $x->y
1523 // take variable from scope of current object
1524 php_report_error(PHP_ERROR, "Assign to class members not supported");
1525 break;
1526 case PHP_OP_CLASS_DEREF: // A::y
1527 // take variable (static) from scope of current class
1528 php_report_error(PHP_ERROR, "Assign to static class members not supported");
1529 break;
1530 default:
1531 //
1532 // Error: expression can not be taken as lvalue
1533 //
1534 php_report_error(PHP_ERROR, "This expression can't be used as lvalue");
1535 }
1536 return lval_node;
1537}
1538
1539static PHP_VALUE_TYPE cast_type_resolve(PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2)
1540{
1541 if ( (op1->type == PHP_VAL_FLOAT) || (op2->type == PHP_VAL_FLOAT) ) {
1542 cast_value_fnum(op1);
1543 cast_value_fnum(op2);
1544 return PHP_VAL_FLOAT;
1545 } else {
1546 cast_value_dnum(op1);
1547 cast_value_dnum(op2);
1548 return PHP_VAL_INT;
1549 }
1550}
1551
1552/*
1553 * Same as simple_math, but result is always bool
1554 */
1555void php_eval_compare(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1556{
1557 result->type = PHP_VAL_BOOL;
1558 if ( (op1->type == PHP_VAL_STRING) || (op2->type == PHP_VAL_STRING) ) {
1559 cast_value_str(op1);
1560 cast_value_str(op2);
1561 int cmp_val = strcmp(op1->str_val, op2->str_val);
1562 switch(op) {
1563 case PHP_OP_EQ:
1564 result->int_val = (cmp_val == 0);
1565 break;
1566 case PHP_OP_NEQ:
1567 result->int_val = (cmp_val != 0);
1568 break;
1569 case PHP_OP_GRT:
1570 result->int_val = (cmp_val > 0);
1571 break;
1572 case PHP_OP_LWR:
1573 result->int_val = (cmp_val < 0);
1574 break;
1575 case PHP_OP_GRT_EQ:
1576 result->int_val = (cmp_val >= 0);
1577 break;
1578 case PHP_OP_LWR_EQ:
1579 result->int_val = (cmp_val <= 0);
1580 break;
1581 default:
1582 php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op");
1583 }
1584 } else {
1585 PHP_VALUE_TYPE restype = cast_type_resolve(op1, op2);
1586 switch(op) {
1587 case PHP_OP_EQ:
1588 if ( restype == PHP_VAL_FLOAT ) {
1589 result->int_val = op1->float_val == op2->float_val;
1590 } else {
1591 result->int_val = op1->int_val == op2->int_val;
1592 }
1593 break;
1594 case PHP_OP_NEQ:
1595 if ( restype == PHP_VAL_FLOAT ) {
1596 result->int_val = op1->float_val != op2->float_val;
1597 } else {
1598 result->int_val = op1->int_val != op2->int_val;
1599 }
1600 break;
1601 case PHP_OP_GRT:
1602 if ( restype == PHP_VAL_FLOAT ) {
1603 result->int_val = op1->float_val > op2->float_val;
1604 } else {
1605 result->int_val = op1->int_val > op2->int_val;
1606 }
1607 break;
1608 case PHP_OP_GRT_EQ:
1609 if ( restype == PHP_VAL_FLOAT ) {
1610 result->int_val = op1->float_val >= op2->float_val;
1611 } else {
1612 result->int_val = op1->int_val >= op2->int_val;
1613 }
1614 break;
1615 case PHP_OP_LWR:
1616 if ( restype == PHP_VAL_FLOAT ) {
1617 result->int_val = op1->float_val < op2->float_val;
1618 } else {
1619 result->int_val = op1->int_val < op2->int_val;
1620 }
1621 break;
1622 case PHP_OP_LWR_EQ:
1623 if ( restype == PHP_VAL_FLOAT ) {
1624 result->int_val = op1->float_val <= op2->float_val;
1625 } else {
1626 result->int_val = op1->int_val <= op2->int_val;
1627 }
1628 break;
1629 default:
1630 php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op");
1631 }
1632 }
1633}
1634
1635void php_eval_simple_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1636{
1637 result->type = cast_type_resolve(op1, op2);
1638 switch(op) {
1639 case PHP_OP_ADD:
1640 if ( result->type == PHP_VAL_FLOAT ) {
1641 result->float_val = op1->float_val + op2->float_val;
1642 } else {
1643 result->int_val = op1->int_val + op2->int_val;
1644 }
1645 break;
1646 case PHP_OP_SUB:
1647 if ( result->type == PHP_VAL_FLOAT ) {
1648 result->float_val = op1->float_val - op2->float_val;
1649 } else {
1650 result->int_val = op1->int_val - op2->int_val;
1651 }
1652 break;
1653 case PHP_OP_MUL:
1654 if ( result->type == PHP_VAL_FLOAT ) {
1655 result->float_val = op1->float_val * op2->float_val;
1656 } else {
1657 result->int_val = op1->int_val * op2->int_val;
1658 }
1659 break;
1660 case PHP_OP_DIV:
1661 if ( result->type == PHP_VAL_FLOAT ) {
1662 result->float_val = op1->float_val / op2->float_val;
1663 } else {
1664 result->int_val = op1->int_val / op2->int_val;
1665 }
1666 break;
1667 default:
1668 php_report_error(PHP_INTERNAL_ERROR, "This op is not simple math");
1669 }
1670}
1671
1672void php_eval_int_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1673{
1674 cast_value_dnum(op1);
1675 cast_value_dnum(op2);
1676 result->type = PHP_VAL_INT;
1677 switch(op) {
1678 case PHP_OP_SHL:
1679 result->int_val = op1->int_val << op2->int_val;
1680 break;
1681 case PHP_OP_SHR:
1682 result->int_val = op1->int_val >> op2->int_val;
1683 break;
1684 case PHP_OP_OR:
1685 result->int_val = op1->int_val | op2->int_val;
1686 break;
1687 case PHP_OP_LOG_OR:
1688 result->int_val = op1->int_val || op2->int_val;
1689 break;
1690 case PHP_OP_AND:
1691 result->int_val = op1->int_val & op2->int_val;
1692 break;
1693 case PHP_OP_LOG_AND:
1694 result->int_val = op1->int_val && op2->int_val;
1695 break;
1696 case PHP_OP_LOG_XOR:
1697 op1->int_val = op1->int_val ? 1 : 0;
1698 op2->int_val = op2->int_val ? 1 : 0;
1699 /* fall through */
1700 case PHP_OP_XOR:
1701 result->int_val = op1->int_val ^ op2->int_val;
1702 break;
1703 default:
1704 php_report_error(PHP_INTERNAL_ERROR, "This op is not int math");
1705 }
1706}
1707
1708//
1709// left = VAR(func_name), right=ARRAY(args)
1710void php_run_func_call(PHP_EXP_NODE *node, PHP_VALUE_NODE *result)
1711{
1712 PHP_EXP_NODE *l_node = node->tree_node.left;
1713 PHP_EXP_NODE *r_node = node->tree_node.right;
1714 if ( (l_node->op != PHP_OP_VAL) || (l_node->val_node.type != PHP_VAL_STRING) ||
1715 (r_node->op != PHP_OP_VAR) || (r_node->var_node->value.type != PHP_VAL_ARRAY) ) {
1716 //
1717 // Internal error: function name must be string value node, and
1718 // params must be an array
1719 //
1720 php_report_error(PHP_INTERNAL_ERROR, "Function call node have wrong data");
1721 return ;
1722 }
1723 PHP_SCOPE_ITEM *si = get_scope_item(g_global_scope, l_node->val_node.str_val);
1724 if ( !si ) {
1725 //
1726 // Error: undeclared symbol
1727 //
1728 php_report_error(PHP_ERROR, "Function [ %s ] is not defined", l_node->val_node.str_val);
1729 return;
1730 }
1731 if ( si->type != PHP_SCOPE_FUNC) {
1732 //
1733 // Error: defined, but wrong type !
1734 //
1735 php_report_error(PHP_ERROR, "Item [ %s ] is not a function", l_node->val_node.str_val);
1736 return;
1737 }
1738 PHP_SYN_NODE *func = si->func;
1739 if ( func->type != PHP_ST_FUNC_DECL ) {
1740 //
1741 // Internal error: node not a function
1742 //
1743 php_report_error(PHP_INTERNAL_ERROR, "Wrong type in function decl node");
1744 return;
1745 }
1746
1747 //
1748 // Switch stack and call function
1749 //
1750
1751 PHP_SYN_FUNC_DECL_NODE *func_decl = func->func_decl;
1752
1753 std::map<std::string, PHP_VAR_NODE *> saved_vars;
1754 func_scope_init(func_decl->params, func_decl->param_count,
1755 (PHP_SCOPE_TABLE_TYPE *)func_decl->scope,
1756 &r_node->var_node->value, saved_vars);
1757
1758 switch_push_scope_table((PHP_SCOPE_TABLE_TYPE *)func_decl->scope);
1759
1760 if ( func_decl->is_native ) {
1761 func_decl->native_ptr(result);
1762 } else {
1763 php_execute(func_decl->code, result);
1764 }
1765
1766 //
1767 // restore stack, free arg list
1768 //
1769 switch_pop_scope_table(0);
1770 func_scope_copy_back(func_decl->params, func_decl->param_count,
1771 (PHP_SCOPE_TABLE_TYPE *)func_decl->scope, &r_node->var_node->value, saved_vars);
1772
1773 //scope_reset_nonstatics(func_decl->scope);
1774
1775}
1776
1777/*
1778 * Theoretically speaking this function must run on generated code. On the
1779 * practical side - I need it to debug syntax tree generation. Later, it can
1780 * be changes to generate code for some kind of bytecode for stack machine
1781 */
1782int php_execute(PHP_SYN_NODE *node, PHP_VALUE_NODE *result)
1783{
1784 if ( !node ) {
1785 return 0;
1786 }
1787 while ( node ) {
1788 int curr_exec_result = 0;
1789 PHP_VALUE_NODE cond_result;
1790 cond_result.type = PHP_VAL_NONE;
1791 switch (node->type) {
1792 case PHP_ST_EXPR:
1793 php_expr_eval(node->node_expr, 0);
1794 break;
1795 case PHP_ST_IF:
1796 php_expr_eval(node->node_if.cond, &cond_result);
1797 cast_value_bool(&cond_result);
1798 if ( cond_result.int_val ) {
1799 if ( node->node_if.code_if ) {
1800 curr_exec_result = php_execute(node->node_if.code_if, result);
1801 }
1802 } else {
1803 if ( node->node_if.code_else ) {
1804 curr_exec_result = php_execute(node->node_if.code_else, result);
1805 }
1806 }
1807 break;
1808 case PHP_ST_RET:
1809 if ( node->node_expr ) {
1810 php_expr_eval(node->node_expr, result);
1811 }
1812 if ( node->next_node ) {
1813 //
1814 // Warning: code after "return" statement
1815 //
1816 php_report_error(PHP_WARNING, "code after 'return'");
1817 }
1818 // "return" is ultimate "break"
1819 curr_exec_result = -0xffff;
1820 break;
1821 case PHP_ST_ECHO: {
1822 PHP_EXP_NODE *curr = node->node_expr;
1823 while (curr) {
1824 php_expr_eval(curr->exp_node, &cond_result);
1825 cast_value_str(&cond_result);
1826 CPhPLibContext::Print(cond_result.str_val);
1827 value_value_free(&cond_result);
1828 curr = curr->next;
1829 }
1830 }
1831 break;
1832 case PHP_ST_CONTINUE:
1833 case PHP_ST_BREAK:
1834 if ( node->node_expr ) {
1835 // 'break' or 'continue' used with an argument
1836 php_expr_eval(node->node_expr, &cond_result);
1837 } else {
1838 // without an argument break or continue just 1 loop
1839 cond_result.type = PHP_VAL_INT;
1840 cond_result.int_val = 1;
1841 }
1842 cast_value_dnum(&cond_result);
1843 if ( node->type == PHP_ST_BREAK ) {
1844 curr_exec_result = -(int)(cond_result.int_val);
1845 } else {
1846 curr_exec_result = cond_result.int_val;
1847 }
1848 break;
1849
1850 case PHP_ST_WHILE:
1851 case PHP_ST_DO_WHILE:
1852 if ( node->type == PHP_ST_WHILE ) {
1853 php_expr_eval(node->node_while.cond, &cond_result);
1854 cast_value_bool(&cond_result);
1855 } else {
1856 cond_result.int_val = 1;
1857 }
1858 while ( cond_result.int_val ) {
1859 // evaluate code within while loop
1860 curr_exec_result = php_execute(node->node_while.code, 0);
1861 // if 'break' was used
1862 if ( curr_exec_result < 0 ) {
1863 // decrease number of loops to break
1864 curr_exec_result++;
1865 // and break current loop
1866 break;
1867 }
1868 // normal execution of loop or continue
1869 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1870 curr_exec_result = 0;
1871 // evaluate 'while' loop conditions
1872 php_expr_eval(node->node_while.cond, &cond_result);
1873 cast_value_bool(&cond_result);
1874 }
1875 // if 'continue' was used with an argument > 1
1876 if ( curr_exec_result > 1 ) {
1877 // decrease number of loops to skip
1878 curr_exec_result--;
1879 // and break current loop
1880 break;
1881 }
1882 }
1883 break;
1884 case PHP_ST_FOR:
1885 php_expr_eval(node->node_for.do_start, &cond_result);
1886 php_expr_eval(node->node_for.cond, &cond_result);
1887 cast_value_bool(&cond_result);
1888 while ( cond_result.int_val ) {
1889 curr_exec_result = php_execute(node->node_for.code, 0);
1890 // handle 'break' and 'continue'
1891 if ( curr_exec_result < 0 ) {
1892 curr_exec_result++;
1893 break;
1894 }
1895 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1896 curr_exec_result = 0;
1897 // evaluate 'for' loop conditions
1898 php_expr_eval(node->node_for.do_next, &cond_result);
1899 php_expr_eval(node->node_for.cond, &cond_result);
1900 cast_value_bool(&cond_result);
1901 }
1902 if ( curr_exec_result > 1 ) {
1903 curr_exec_result--;
1904 break;
1905 }
1906 }
1907 break;
1908 case PHP_ST_FOREACH: {
1909 PHP_VAR_NODE *elems = php_expr_eval_lvalue(node->node_foreach.elems);
1910 if ( !elems || (elems->value.type != PHP_VAL_ARRAY) ) {
1911 php_report_error(PHP_ERROR, "Argument of 'foreach' must be array");
1912 break;
1913 }
1914 PHP_ARRAY_TYPE *array = (PHP_ARRAY_TYPE *)elems->value.ptr_val;
1915 PHP_SCOPE_ITEM *i_key = node->node_foreach.i_key;
1916 // keys in array are string values.
1917 if ( i_key ) {
1918 i_key->var->value.type = PHP_VAL_STRING;
1919 }
1920 PHP_SCOPE_ITEM *i_val = node->node_foreach.i_val;
1921 array->current = array->sorted_keys.begin();
1922 while ( array->current != array->sorted_keys.end() ) {
1923 if ( i_key ) {
1924 PHP_VALUE_NODE tmp_val;
1925 tmp_val.type = PHP_VAL_STRING;
1926 tmp_val.str_val = (char *)array->current->c_str();
1927 value_value_assign(&i_key->var->value, &tmp_val);
1928 }
1929 PHP_VALUE_NODE *curr_value = &array->array[*array->current]->value;
1930 value_value_assign(&i_val->var->value, curr_value);
1931 curr_exec_result = php_execute(node->node_foreach.code, 0);
1932 // clean up
1933 if ( i_key ) {
1934 value_value_free(&i_key->var->value);
1935 }
1936 if ( node->node_foreach.byref ) {
1937 value_value_assign(curr_value, &i_val->var->value);
1938 }
1939 value_value_free(&i_val->var->value);
1940 // handle 'break' and 'continue'
1941 if ( curr_exec_result < 0 ) {
1942 curr_exec_result++;
1943 break;
1944 }
1945 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1946 curr_exec_result = 0;
1947 // next element
1948 array->current++;
1949 }
1950 if ( curr_exec_result > 1 ) {
1951 curr_exec_result--;
1952 break;
1953 }
1954 }
1955 }
1956 break;
1957 case PHP_ST_SWITCH: {
1958 PHP_SYN_NODE *cur_exec = 0;
1959 // evaluate switch argument
1960 php_expr_eval(node->node_switch.cond, &cond_result);
1961 // loop through list of case statements
1962 PHP_EXP_NODE *curr = node->node_switch.case_list;
1963 while (curr) {
1964 PHP_VALUE_NODE cur_value, cmp_result;
1965 cur_value.type = cmp_result.type = PHP_VAL_NONE;
1966 // TODO make amuleweb not crash when 'default' is used
1967 php_expr_eval(curr->exp_node->tree_node.left, &cur_value);
1968
1969 // switch argument equal to case argument?
1970 php_eval_compare(PHP_OP_EQ, &cur_value, &cond_result, &cmp_result);
1971 if ( cmp_result.int_val ) {
1972 // execute code and rest of case statements
1973 cur_exec = static_cast<PHP_SYN_NODE *>(curr->exp_node->tree_node.syn_right);
1974 break;
1975 }
1976 curr = curr->next;
1977 }
1978 if ( cur_exec ) {
1979 curr_exec_result = php_execute(cur_exec, result);
1980 // break
1981 if (curr_exec_result < 0) curr_exec_result++;
1982 // continue
1983 if (curr_exec_result > 0) curr_exec_result--;
1984 }
1985 }
1986 break;
1987 default: ;
1988 }
1989 if ( curr_exec_result ) {
1990 return curr_exec_result;
1991 }
1992 node = node->next_node;
1993 }
1994 // everything ok, keep going
1995 return 0;
1996}
1997
1998
1999//
2000// call it when something gone wrong
2001//
2002void php_report_error(PHP_MSG_TYPE err_type, const char *msg, ...)
2003{
2004 //
2005 // hope my error message will never be that big.
2006 //
2007 // security is ok, since _user_ errors are not reporting thru
2008 // this function, but handled by script itself.
2009 // However, badly written script MAY force user-supplied data to
2010 // leak here and create stack overrun exploit. Be warned.
2011 //
2012 char msgbuf[1024];
2013 const char *type_msg = 0;
2014 switch(err_type) {
2015 case PHP_MESAGE:
2016 type_msg = "PHP:";
2017 break;
2018 case PHP_WARNING:
2019 type_msg = "PHP Warning:";
2020 break;
2021 case PHP_ERROR:
2022 type_msg = "PHP Error:";
2023 break;
2024 case PHP_INTERNAL_ERROR:
2025 type_msg = "PHP Internal Error:";
2026 break;
2027 }
2028
2029 va_list args;
2030 va_start(args, msg)__builtin_va_start(args, msg);
2031 vsnprintf(msgbuf, sizeof(msgbuf), msg, args);
2032 va_end(args)__builtin_va_end(args);
2033
2034 printf("%s %s\n", type_msg, msgbuf);
2035 assert(err_type != PHP_INTERNAL_ERROR)(static_cast <bool> (err_type != PHP_INTERNAL_ERROR) ? void
(0) : __assert_fail ("err_type != PHP_INTERNAL_ERROR", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
2036}
2037
2038
2039int phperror(char *s)
2040{
2041 printf("ERROR in grammar %s after [%s] near line %d\n", s, phptext, phplineno);
2042 return 0;
2043}
2044
2045// File_checked_for_headers