XCache is a fast, stable PHP opcode cacher that has been proven and is now running on production servers under high load. https://xcache.lighttpd.net/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

841 lines
22 KiB

  1. #include "xcache.h"
  2. #include "stack.h"
  3. #include "xcache_globals.h"
  4. #include "utils.h"
  5. #ifdef ZEND_ENGINE_2_1
  6. #include "zend_vm.h"
  7. #endif
  8. #include "opcode_spec.h"
  9. #undef NDEBUG
  10. #include "assert.h"
  11. #ifndef max
  12. #define max(a, b) ((a) < (b) ? (b) : (a))
  13. #endif
  14. #ifndef ZEND_VM_SET_OPCODE_HANDLER
  15. # define ZEND_VM_SET_OPCODE_HANDLER(opline) do { } while (0)
  16. #endif
  17. #define OP_ZVAL_DTOR(op) do { \
  18. Z_UNSET_ISREF((op).u.constant); \
  19. zval_dtor(&(op).u.constant); \
  20. } while(0)
  21. xc_compile_result_t *xc_compile_result_init(xc_compile_result_t *cr, /* {{{ */
  22. zend_op_array *op_array,
  23. HashTable *function_table,
  24. HashTable *class_table)
  25. {
  26. if (cr) {
  27. cr->alloc = 0;
  28. }
  29. else {
  30. cr = emalloc(sizeof(xc_compile_result_t));
  31. cr->alloc = 1;
  32. }
  33. cr->op_array = op_array;
  34. cr->function_table = function_table;
  35. cr->class_table = class_table;
  36. return cr;
  37. }
  38. /* }}} */
  39. xc_compile_result_t *xc_compile_result_init_cur(xc_compile_result_t *cr, zend_op_array *op_array TSRMLS_DC) /* {{{ */
  40. {
  41. return xc_compile_result_init(cr, op_array, CG(function_table), CG(class_table));
  42. }
  43. /* }}} */
  44. void xc_compile_result_free(xc_compile_result_t *cr) /* {{{ */
  45. {
  46. if (cr->alloc) {
  47. efree(cr);
  48. }
  49. }
  50. /* }}} */
  51. int xc_apply_function(zend_function *zf, apply_func_t applyer TSRMLS_DC) /* {{{ */
  52. {
  53. switch (zf->type) {
  54. case ZEND_USER_FUNCTION:
  55. case ZEND_EVAL_CODE:
  56. return applyer(&zf->op_array TSRMLS_CC);
  57. break;
  58. case ZEND_INTERNAL_FUNCTION:
  59. case ZEND_OVERLOADED_FUNCTION:
  60. break;
  61. EMPTY_SWITCH_DEFAULT_CASE();
  62. }
  63. return 0;
  64. }
  65. /* }}} */
  66. typedef struct {
  67. apply_func_t applyer;
  68. zend_class_entry *ce;
  69. } xc_apply_method_info;
  70. int xc_apply_method(zend_function *zf, xc_apply_method_info *mi TSRMLS_DC) /* {{{ */
  71. {
  72. /* avoid duplicate apply for shadowed method */
  73. #ifdef ZEND_ENGINE_2
  74. if (mi->ce != zf->common.scope) {
  75. /* fprintf(stderr, "avoided duplicate %s\n", zf->common.function_name); */
  76. return 0;
  77. }
  78. #else
  79. char *name = zf->common.function_name;
  80. int name_s = strlen(name) + 1;
  81. zend_class_entry *ce;
  82. zend_function *ptr;
  83. for (ce = mi->ce->parent; ce; ce = ce->parent) {
  84. if (zend_hash_find(&ce->function_table, name, name_s, (void **) &ptr) == SUCCESS) {
  85. if (ptr->op_array.refcount == zf->op_array.refcount) {
  86. return 0;
  87. }
  88. }
  89. }
  90. #endif
  91. return xc_apply_function(zf, mi->applyer TSRMLS_CC);
  92. }
  93. /* }}} */
  94. #if 0
  95. int xc_apply_class(zend_class_entry *ce, apply_func_t applyer TSRMLS_DC) /* {{{ */
  96. {
  97. xc_apply_method_info mi;
  98. mi.applyer = applyer;
  99. mi.ce = ce;
  100. zend_hash_apply_with_argument(&(ce->function_table), (apply_func_arg_t) xc_apply_method, &mi TSRMLS_CC);
  101. return 0;
  102. }
  103. /* }}} */
  104. #endif
  105. static int xc_apply_cest(xc_cest_t *cest, apply_func_t applyer TSRMLS_DC) /* {{{ */
  106. {
  107. xc_apply_method_info mi;
  108. mi.applyer = applyer;
  109. mi.ce = CestToCePtr(*cest);
  110. zend_hash_apply_with_argument(&(CestToCePtr(*cest)->function_table), (apply_func_arg_t) xc_apply_method, &mi TSRMLS_CC);
  111. return 0;
  112. }
  113. /* }}} */
  114. int xc_apply_op_array(xc_compile_result_t *cr, apply_func_t applyer TSRMLS_DC) /* {{{ */
  115. {
  116. zend_hash_apply_with_argument(cr->function_table, (apply_func_arg_t) xc_apply_function, (void *) applyer TSRMLS_CC);
  117. zend_hash_apply_with_argument(cr->class_table, (apply_func_arg_t) xc_apply_cest, (void *) applyer TSRMLS_CC);
  118. return applyer(cr->op_array TSRMLS_CC);
  119. }
  120. /* }}} */
  121. int xc_undo_pass_two(zend_op_array *op_array TSRMLS_DC) /* {{{ */
  122. {
  123. zend_op *opline, *end;
  124. if (!op_array->done_pass_two) {
  125. return 0;
  126. }
  127. opline = op_array->opcodes;
  128. end = opline + op_array->last;
  129. while (opline < end) {
  130. #ifdef ZEND_ENGINE_2_1
  131. switch (opline->opcode) {
  132. #ifdef ZEND_GOTO
  133. case ZEND_GOTO:
  134. #endif
  135. case ZEND_JMP:
  136. opline->op1.u.opline_num = opline->op1.u.jmp_addr - op_array->opcodes;
  137. assert(opline->op1.u.opline_num < op_array->last);
  138. break;
  139. case ZEND_JMPZ:
  140. case ZEND_JMPNZ:
  141. case ZEND_JMPZ_EX:
  142. case ZEND_JMPNZ_EX:
  143. #ifdef ZEND_JMP_SET
  144. case ZEND_JMP_SET:
  145. #endif
  146. opline->op2.u.opline_num = opline->op2.u.jmp_addr - op_array->opcodes;
  147. assert(opline->op2.u.opline_num < op_array->last);
  148. break;
  149. }
  150. #endif
  151. opline++;
  152. }
  153. op_array->done_pass_two = 0;
  154. return 0;
  155. }
  156. /* }}} */
  157. int xc_redo_pass_two(zend_op_array *op_array TSRMLS_DC) /* {{{ */
  158. {
  159. zend_op *opline, *end;
  160. if (op_array->done_pass_two) {
  161. return 0;
  162. }
  163. /*
  164. op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
  165. op_array->size = op_array->last;
  166. */
  167. opline = op_array->opcodes;
  168. end = opline + op_array->last;
  169. while (opline < end) {
  170. if (opline->op1.op_type == IS_CONST) {
  171. Z_SET_ISREF(opline->op1.u.constant);
  172. Z_SET_REFCOUNT(opline->op1.u.constant, 2); /* Make sure is_ref won't be reset */
  173. }
  174. if (opline->op2.op_type == IS_CONST) {
  175. Z_SET_ISREF(opline->op2.u.constant);
  176. Z_SET_REFCOUNT(opline->op2.u.constant, 2);
  177. }
  178. #ifdef ZEND_ENGINE_2_1
  179. switch (opline->opcode) {
  180. #ifdef ZEND_GOTO
  181. case ZEND_GOTO:
  182. #endif
  183. case ZEND_JMP:
  184. assert(opline->op1.u.opline_num < op_array->last);
  185. opline->op1.u.jmp_addr = op_array->opcodes + opline->op1.u.opline_num;
  186. break;
  187. case ZEND_JMPZ:
  188. case ZEND_JMPNZ:
  189. case ZEND_JMPZ_EX:
  190. case ZEND_JMPNZ_EX:
  191. #ifdef ZEND_JMP_SET
  192. case ZEND_JMP_SET:
  193. #endif
  194. assert(opline->op2.u.opline_num < op_array->last);
  195. opline->op2.u.jmp_addr = op_array->opcodes + opline->op2.u.opline_num;
  196. break;
  197. }
  198. ZEND_VM_SET_OPCODE_HANDLER(opline);
  199. #endif
  200. opline++;
  201. }
  202. op_array->done_pass_two = 1;
  203. return 0;
  204. }
  205. /* }}} */
  206. #ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
  207. static void xc_fix_opcode_ex_znode(int tofix, xc_op_spec_t spec, znode *znode, int type TSRMLS_DC) /* {{{ */
  208. {
  209. #ifdef ZEND_ENGINE_2
  210. if ((znode->op_type != IS_UNUSED && (spec == OPSPEC_UCLASS || spec == OPSPEC_CLASS)) ||
  211. spec == OPSPEC_FETCH) {
  212. if (tofix) {
  213. switch (znode->op_type) {
  214. case IS_VAR:
  215. case IS_TMP_VAR:
  216. break;
  217. default:
  218. /* TODO: data lost, find a way to keep it */
  219. /* assert(znode->op_type == IS_CONST); */
  220. znode->op_type = IS_TMP_VAR;
  221. }
  222. }
  223. }
  224. switch (znode->op_type) {
  225. case IS_TMP_VAR:
  226. case IS_VAR:
  227. if (tofix) {
  228. znode->u.var /= sizeof(temp_variable);
  229. }
  230. else {
  231. znode->u.var *= sizeof(temp_variable);
  232. }
  233. }
  234. #endif
  235. }
  236. /* }}} */
  237. static void xc_fix_opcode_ex(zend_op_array *op_array, int tofix TSRMLS_DC) /* {{{ */
  238. {
  239. zend_op *opline;
  240. zend_uint i;
  241. opline = op_array->opcodes;
  242. for (i = 0; i < op_array->last; i ++, opline ++) {
  243. /* 3rd optimizer may have ... */
  244. if (opline->opcode < xc_get_opcode_spec_count()) {
  245. const xc_opcode_spec_t *spec;
  246. spec = xc_get_opcode_spec(opline->opcode);
  247. xc_fix_opcode_ex_znode(tofix, spec->op1, &opline->op1, 0 TSRMLS_CC);
  248. xc_fix_opcode_ex_znode(tofix, spec->op2, &opline->op2, 1 TSRMLS_CC);
  249. xc_fix_opcode_ex_znode(tofix, spec->res, &opline->result, 2 TSRMLS_CC);
  250. }
  251. }
  252. }
  253. /* }}} */
  254. int xc_fix_opcode(zend_op_array *op_array TSRMLS_DC) /* {{{ */
  255. {
  256. xc_fix_opcode_ex(op_array, 1 TSRMLS_CC);
  257. return 0;
  258. }
  259. /* }}} */
  260. int xc_undo_fix_opcode(zend_op_array *op_array TSRMLS_DC) /* {{{ */
  261. {
  262. xc_fix_opcode_ex(op_array, 0 TSRMLS_CC);
  263. return 0;
  264. }
  265. /* }}} */
  266. #endif
  267. int xc_foreach_early_binding_class(zend_op_array *op_array, void (*callback)(zend_op *opline, int oplineno, void *data TSRMLS_DC), void *data TSRMLS_DC) /* {{{ */
  268. {
  269. zend_op *opline, *begin, *end, *next = NULL;
  270. opline = begin = op_array->opcodes;
  271. end = opline + op_array->last;
  272. while (opline < end) {
  273. switch (opline->opcode) {
  274. #ifdef ZEND_GOTO
  275. case ZEND_GOTO:
  276. #endif
  277. case ZEND_JMP:
  278. next = begin + opline->op1.u.opline_num;
  279. break;
  280. case ZEND_JMPZNZ:
  281. next = begin + max(opline->op2.u.opline_num, opline->extended_value);
  282. break;
  283. case ZEND_JMPZ:
  284. case ZEND_JMPNZ:
  285. case ZEND_JMPZ_EX:
  286. case ZEND_JMPNZ_EX:
  287. #ifdef ZEND_JMP_SET
  288. case ZEND_JMP_SET:
  289. #endif
  290. next = begin + opline->op2.u.opline_num;
  291. break;
  292. case ZEND_RETURN:
  293. opline = end;
  294. break;
  295. #ifdef ZEND_ENGINE_2
  296. case ZEND_DECLARE_INHERITED_CLASS:
  297. callback(opline, opline - begin, data TSRMLS_CC);
  298. break;
  299. #else
  300. case ZEND_DECLARE_FUNCTION_OR_CLASS:
  301. if (opline->extended_value == ZEND_DECLARE_INHERITED_CLASS) {
  302. callback(opline, opline - begin, data TSRMLS_CC);
  303. }
  304. break;
  305. #endif
  306. }
  307. if (opline < next) {
  308. opline = next;
  309. }
  310. else {
  311. opline ++;
  312. }
  313. }
  314. return SUCCESS;
  315. }
  316. /* }}} */
  317. #ifndef ZEND_COMPILE_DELAYED_BINDING
  318. static int xc_do_early_binding(zend_op_array *op_array, HashTable *class_table, int oplineno TSRMLS_DC) /* {{{ */
  319. {
  320. zend_op *opline;
  321. TRACE("binding %d", oplineno);
  322. assert(oplineno >= 0);
  323. /* do early binding */
  324. opline = &(op_array->opcodes[oplineno]);
  325. switch (opline->opcode) {
  326. #ifdef ZEND_ENGINE_2
  327. case ZEND_DECLARE_INHERITED_CLASS:
  328. {
  329. zval *parent_name;
  330. zend_class_entry **pce;
  331. /* don't early-bind classes that implement interfaces */
  332. if ((opline + 1)->opcode == ZEND_FETCH_CLASS && (opline + 2)->opcode == ZEND_ADD_INTERFACE) {
  333. return FAILURE;
  334. }
  335. parent_name = &(opline - 1)->op2.u.constant;
  336. TRACE("binding with parent %s", Z_STRVAL_P(parent_name));
  337. if (zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) {
  338. return FAILURE;
  339. }
  340. if (do_bind_inherited_class(opline, class_table, *pce, 1 TSRMLS_CC) == NULL) {
  341. return FAILURE;
  342. }
  343. }
  344. /* clear unnecessary ZEND_FETCH_CLASS opcode */
  345. if (opline > op_array->opcodes
  346. && (opline - 1)->opcode == ZEND_FETCH_CLASS) {
  347. zend_op *fetch_class_opline = opline - 1;
  348. TRACE("%s %p", Z_STRVAL(fetch_class_opline->op2.u.constant), Z_STRVAL(fetch_class_opline->op2.u.constant));
  349. OP_ZVAL_DTOR(fetch_class_opline->op2);
  350. fetch_class_opline->opcode = ZEND_NOP;
  351. ZEND_VM_SET_OPCODE_HANDLER(fetch_class_opline);
  352. memset(&fetch_class_opline->op1, 0, sizeof(znode));
  353. memset(&fetch_class_opline->op2, 0, sizeof(znode));
  354. SET_UNUSED(fetch_class_opline->op1);
  355. SET_UNUSED(fetch_class_opline->op2);
  356. SET_UNUSED(fetch_class_opline->result);
  357. }
  358. /* clear unnecessary ZEND_VERIFY_ABSTRACT_CLASS opcode */
  359. if ((opline + 1)->opcode == ZEND_VERIFY_ABSTRACT_CLASS) {
  360. zend_op *abstract_op = opline + 1;
  361. memset(abstract_op, 0, sizeof(abstract_op[0]));
  362. abstract_op->lineno = 0;
  363. SET_UNUSED(abstract_op->op1);
  364. SET_UNUSED(abstract_op->op2);
  365. SET_UNUSED(abstract_op->result);
  366. abstract_op->opcode = ZEND_NOP;
  367. ZEND_VM_SET_OPCODE_HANDLER(abstract_op);
  368. }
  369. #else
  370. case ZEND_DECLARE_FUNCTION_OR_CLASS:
  371. if (do_bind_function_or_class(opline, NULL, class_table, 1) == FAILURE) {
  372. return FAILURE;
  373. }
  374. #endif
  375. break;
  376. default:
  377. return FAILURE;
  378. }
  379. zend_hash_del(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len);
  380. OP_ZVAL_DTOR(opline->op1);
  381. OP_ZVAL_DTOR(opline->op2);
  382. opline->opcode = ZEND_NOP;
  383. ZEND_VM_SET_OPCODE_HANDLER(opline);
  384. memset(&opline->op1, 0, sizeof(znode));
  385. memset(&opline->op2, 0, sizeof(znode));
  386. SET_UNUSED(opline->op1);
  387. SET_UNUSED(opline->op2);
  388. return SUCCESS;
  389. }
  390. /* }}} */
  391. #endif
  392. #ifdef HAVE_XCACHE_CONSTANT
  393. void xc_install_constant(char *filename, zend_constant *constant, zend_uchar type, zstr key, uint len, ulong h TSRMLS_DC) /* {{{ */
  394. {
  395. if (zend_u_hash_add(EG(zend_constants), type, key, len,
  396. constant, sizeof(zend_constant),
  397. NULL
  398. ) == FAILURE) {
  399. CG(zend_lineno) = 0;
  400. #ifdef IS_UNICODE
  401. zend_error(E_NOTICE, "Constant %R already defined", type, key);
  402. #else
  403. zend_error(E_NOTICE, "Constant %s already defined", key);
  404. #endif
  405. free(ZSTR_V(constant->name));
  406. if (!(constant->flags & CONST_PERSISTENT)) {
  407. zval_dtor(&constant->value);
  408. }
  409. }
  410. }
  411. /* }}} */
  412. #endif
  413. void xc_install_function(char *filename, zend_function *func, zend_uchar type, zstr key, uint len, ulong h TSRMLS_DC) /* {{{ */
  414. {
  415. zend_bool istmpkey;
  416. if (func->type == ZEND_USER_FUNCTION) {
  417. #ifdef IS_UNICODE
  418. istmpkey = (type == IS_STRING && ZSTR_S(key)[0] == 0) || ZSTR_U(key)[0] == 0;
  419. #else
  420. istmpkey = ZSTR_S(key)[0] == 0;
  421. #endif
  422. if (istmpkey) {
  423. zend_u_hash_update(CG(function_table), type, key, len,
  424. func, sizeof(zend_op_array),
  425. NULL
  426. );
  427. }
  428. else if (zend_u_hash_add(CG(function_table), type, key, len,
  429. func, sizeof(zend_op_array),
  430. NULL
  431. ) == FAILURE) {
  432. CG(zend_lineno) = ZESW(func->op_array.opcodes[0].lineno, func->op_array.line_start);
  433. #ifdef IS_UNICODE
  434. zend_error(E_ERROR, "Cannot redeclare %R()", type, key);
  435. #else
  436. zend_error(E_ERROR, "Cannot redeclare %s()", key);
  437. #endif
  438. }
  439. }
  440. }
  441. /* }}} */
  442. ZESW(xc_cest_t *, void) xc_install_class(char *filename, xc_cest_t *cest, int oplineno, zend_uchar type, zstr key, uint len, ulong h TSRMLS_DC) /* {{{ */
  443. {
  444. zend_bool istmpkey;
  445. zend_class_entry *cep = CestToCePtr(*cest);
  446. ZESW(void *stored_ce_ptr, NOTHING);
  447. #ifdef IS_UNICODE
  448. istmpkey = (type == IS_STRING && ZSTR_S(key)[0] == 0) || ZSTR_U(key)[0] == 0;
  449. #else
  450. istmpkey = ZSTR_S(key)[0] == 0;
  451. #endif
  452. if (istmpkey) {
  453. zend_u_hash_quick_update(CG(class_table), type, key, len, h,
  454. cest, sizeof(xc_cest_t),
  455. ZESW(&stored_ce_ptr, NULL)
  456. );
  457. #ifndef ZEND_COMPILE_DELAYED_BINDING
  458. if (oplineno != -1) {
  459. xc_do_early_binding(CG(active_op_array), CG(class_table), oplineno TSRMLS_CC);
  460. }
  461. #endif
  462. }
  463. else if (zend_u_hash_quick_add(CG(class_table), type, key, len, h,
  464. cest, sizeof(xc_cest_t),
  465. ZESW(&stored_ce_ptr, NULL)
  466. ) == FAILURE) {
  467. CG(zend_lineno) = ZESW(0, cep->line_start);
  468. #ifdef IS_UNICODE
  469. zend_error(E_ERROR, "Cannot redeclare class %R", type, cep->name);
  470. #else
  471. zend_error(E_ERROR, "Cannot redeclare class %s", cep->name);
  472. #endif
  473. assert(oplineno == -1);
  474. }
  475. ZESW(return (xc_cest_t *) stored_ce_ptr, NOTHING);
  476. }
  477. /* }}} */
  478. /* sandbox {{{ */
  479. #undef TG
  480. #undef OG
  481. #define TG(x) (sandbox->tmp_##x)
  482. #define OG(x) (sandbox->orig_##x)
  483. /* }}} */
  484. #ifdef ZEND_ENGINE_2_1
  485. static zend_bool xc_auto_global_callback(char *name, uint name_len TSRMLS_DC) /* {{{ */
  486. {
  487. zend_auto_global *auto_global;
  488. if (zend_u_hash_find(CG(auto_globals), UG(unicode) ? IS_UNICODE : IS_STRING, ZSTR(name), name_len + 1, (void **) &auto_global) == FAILURE) {
  489. return 1;
  490. }
  491. return 0;
  492. }
  493. /* }}} */
  494. static int xc_auto_global_arm(zend_auto_global *auto_global TSRMLS_DC) /* {{{ */
  495. {
  496. if (auto_global->auto_global_callback) {
  497. auto_global->armed = 1;
  498. auto_global->auto_global_callback = xc_auto_global_callback;
  499. }
  500. else {
  501. auto_global->armed = 0;
  502. }
  503. return ZEND_HASH_APPLY_KEEP;
  504. }
  505. /* }}} */
  506. #endif
  507. void xc_hash_copy_if(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, xc_if_func_t checker) /* {{{ */
  508. {
  509. Bucket *p;
  510. void *new_entry;
  511. zend_bool setTargetPointer;
  512. setTargetPointer = !target->pInternalPointer;
  513. p = source->pListHead;
  514. while (p) {
  515. if (checker(p->pData)) {
  516. if (setTargetPointer && source->pInternalPointer == p) {
  517. target->pInternalPointer = NULL;
  518. }
  519. if (p->nKeyLength) {
  520. zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &new_entry);
  521. } else {
  522. zend_hash_index_update(target, p->h, p->pData, size, &new_entry);
  523. }
  524. if (pCopyConstructor) {
  525. pCopyConstructor(new_entry);
  526. }
  527. }
  528. p = p->pListNext;
  529. }
  530. if (!target->pInternalPointer) {
  531. target->pInternalPointer = target->pListHead;
  532. }
  533. }
  534. /* }}} */
  535. #ifdef HAVE_XCACHE_CONSTANT
  536. static zend_bool xc_is_internal_zend_constant(zend_constant *c) /* {{{ */
  537. {
  538. return (c->flags & CONST_PERSISTENT) ? 1 : 0;
  539. }
  540. /* }}} */
  541. void xc_zend_constant_ctor(zend_constant *c) /* {{{ */
  542. {
  543. assert((c->flags & CONST_PERSISTENT));
  544. #ifdef IS_UNICODE
  545. c->name.u = zend_ustrndup(c->name.u, c->name_len - 1);
  546. #else
  547. c->name = zend_strndup(c->name, c->name_len - 1);
  548. #endif
  549. }
  550. /* }}} */
  551. void xc_zend_constant_dtor(zend_constant *c) /* {{{ */
  552. {
  553. free(ZSTR_U(c->name));
  554. }
  555. /* }}} */
  556. void xc_copy_internal_zend_constants(HashTable *target, HashTable *source) /* {{{ */
  557. {
  558. zend_constant tmp_const;
  559. xc_hash_copy_if(target, source, (copy_ctor_func_t) xc_zend_constant_ctor, (void *) &tmp_const, sizeof(zend_constant), (xc_if_func_t) xc_is_internal_zend_constant);
  560. }
  561. /* }}} */
  562. #endif
  563. xc_sandbox_t *xc_sandbox_init(xc_sandbox_t *sandbox, char *filename TSRMLS_DC) /* {{{ */
  564. {
  565. HashTable *h;
  566. if (sandbox) {
  567. memset(sandbox, 0, sizeof(sandbox[0]));
  568. }
  569. else {
  570. ECALLOC_ONE(sandbox);
  571. sandbox->alloc = 1;
  572. }
  573. memcpy(&OG(included_files), &EG(included_files), sizeof(EG(included_files)));
  574. #ifdef HAVE_XCACHE_CONSTANT
  575. OG(zend_constants) = EG(zend_constants);
  576. EG(zend_constants) = &TG(zend_constants);
  577. #endif
  578. OG(function_table) = CG(function_table);
  579. CG(function_table) = &TG(function_table);
  580. OG(class_table) = CG(class_table);
  581. CG(class_table) = &TG(class_table);
  582. EG(class_table) = CG(class_table);
  583. #ifdef ZEND_ENGINE_2_1
  584. OG(auto_globals) = CG(auto_globals);
  585. CG(auto_globals) = &TG(auto_globals);
  586. #endif
  587. TG(included_files) = &EG(included_files);
  588. zend_hash_init_ex(TG(included_files), 5, NULL, NULL, 0, 1);
  589. #ifdef HAVE_XCACHE_CONSTANT
  590. h = OG(zend_constants);
  591. zend_hash_init_ex(&TG(zend_constants), 20, NULL, h->pDestructor, h->persistent, h->bApplyProtection);
  592. xc_copy_internal_zend_constants(&TG(zend_constants), &XG(internal_constant_table));
  593. {
  594. zend_constant tmp_const;
  595. zend_hash_copy(&TG(zend_constants), &XG(internal_constant_table), (copy_ctor_func_t) xc_zend_constant_ctor, (void *) &tmp_const, sizeof(tmp_const));
  596. }
  597. TG(internal_constant_tail) = TG(zend_constants).pListTail;
  598. #endif
  599. h = OG(function_table);
  600. zend_hash_init_ex(&TG(function_table), 128, NULL, h->pDestructor, h->persistent, h->bApplyProtection);
  601. {
  602. zend_function tmp_func;
  603. zend_hash_copy(&TG(function_table), &XG(internal_function_table), NULL, (void *) &tmp_func, sizeof(tmp_func));
  604. }
  605. TG(internal_function_tail) = TG(function_table).pListTail;
  606. h = OG(class_table);
  607. zend_hash_init_ex(&TG(class_table), 16, NULL, h->pDestructor, h->persistent, h->bApplyProtection);
  608. #if 0 && TODO
  609. {
  610. xc_cest_t tmp_cest;
  611. zend_hash_copy(&TG(class_table), &XG(internal_class_table), NULL, (void *) &tmp_cest, sizeof(tmp_cest));
  612. }
  613. #endif
  614. TG(internal_class_tail) = TG(class_table).pListTail;
  615. #ifdef ZEND_ENGINE_2_1
  616. /* shallow copy, don't destruct */
  617. h = OG(auto_globals);
  618. zend_hash_init_ex(&TG(auto_globals), 8, NULL, NULL, h->persistent, h->bApplyProtection);
  619. {
  620. zend_auto_global tmp_autoglobal;
  621. zend_hash_copy(&TG(auto_globals), OG(auto_globals), NULL, (void *) &tmp_autoglobal, sizeof(tmp_autoglobal));
  622. zend_hash_apply(&TG(auto_globals), (apply_func_t) xc_auto_global_arm TSRMLS_CC);
  623. }
  624. #endif
  625. sandbox->filename = filename;
  626. #ifdef E_STRICT
  627. sandbox->orig_user_error_handler_error_reporting = EG(user_error_handler_error_reporting);
  628. EG(user_error_handler_error_reporting) &= ~E_STRICT;
  629. #endif
  630. #ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
  631. sandbox->orig_compiler_options = CG(compiler_options);
  632. /* Using ZEND_COMPILE_IGNORE_INTERNAL_CLASSES for ZEND_FETCH_CLASS_RT_NS_CHECK
  633. */
  634. CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES | ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_DELAYED_BINDING;
  635. #endif
  636. return sandbox;
  637. }
  638. /* }}} */
  639. #ifndef ZEND_COMPILE_DELAYED_BINDING
  640. static void xc_early_binding_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
  641. {
  642. xc_sandbox_t *sandbox = (xc_sandbox_t *) data;
  643. xc_do_early_binding(CG(active_op_array), OG(class_table), oplineno TSRMLS_CC);
  644. }
  645. /* }}} */
  646. #endif
  647. static void xc_sandbox_install(xc_sandbox_t *sandbox, xc_install_action_t install TSRMLS_DC) /* {{{ */
  648. {
  649. zend_uint i;
  650. Bucket *b;
  651. #ifdef HAVE_XCACHE_CONSTANT
  652. b = TG(internal_constant_tail) ? TG(internal_constant_tail)->pListNext : TG(zend_constants).pListHead;
  653. /* install constants */
  654. while (b != NULL) {
  655. zend_constant *c = (zend_constant*) b->pData;
  656. xc_install_constant(sandbox->filename, c,
  657. BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
  658. b = b->pListNext;
  659. }
  660. #endif
  661. b = TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : TG(function_table).pListHead;
  662. /* install function */
  663. while (b != NULL) {
  664. zend_function *func = (zend_function*) b->pData;
  665. xc_install_function(sandbox->filename, func,
  666. BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
  667. b = b->pListNext;
  668. }
  669. b = TG(internal_class_tail) ? TG(internal_class_tail)->pListNext : TG(class_table).pListHead;
  670. /* install class */
  671. while (b != NULL) {
  672. xc_install_class(sandbox->filename, (xc_cest_t*) b->pData, -1,
  673. BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
  674. b = b->pListNext;
  675. }
  676. #ifdef ZEND_ENGINE_2_1
  677. /* trigger auto_globals jit */
  678. for (b = TG(auto_globals).pListHead; b != NULL; b = b->pListNext) {
  679. zend_auto_global *auto_global = (zend_auto_global *) b->pData;
  680. /* check if actived */
  681. if (auto_global->auto_global_callback && !auto_global->armed) {
  682. zend_u_is_auto_global(BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), auto_global->name_len TSRMLS_CC);
  683. }
  684. }
  685. #endif
  686. if (install != XC_InstallNoBinding) {
  687. #ifdef ZEND_COMPILE_DELAYED_BINDING
  688. zend_do_delayed_early_binding(CG(active_op_array) TSRMLS_CC);
  689. #else
  690. xc_undo_pass_two(CG(active_op_array) TSRMLS_CC);
  691. xc_foreach_early_binding_class(CG(active_op_array), xc_early_binding_cb, (void *) sandbox TSRMLS_CC);
  692. xc_redo_pass_two(CG(active_op_array) TSRMLS_CC);
  693. #endif
  694. }
  695. i = 1;
  696. zend_hash_add(&OG(included_files), sandbox->filename, strlen(sandbox->filename) + 1, (void *)&i, sizeof(int), NULL);
  697. }
  698. /* }}} */
  699. void xc_sandbox_free(xc_sandbox_t *sandbox, xc_install_action_t install TSRMLS_DC) /* {{{ */
  700. {
  701. /* restore first first install function/class */
  702. #ifdef HAVE_XCACHE_CONSTANT
  703. EG(zend_constants) = OG(zend_constants);
  704. #endif
  705. CG(function_table) = OG(function_table);
  706. CG(class_table) = OG(class_table);
  707. EG(class_table) = CG(class_table);
  708. #ifdef ZEND_ENGINE_2_1
  709. CG(auto_globals) = OG(auto_globals);
  710. #endif
  711. if (install != XC_NoInstall) {
  712. CG(in_compilation) = 1;
  713. CG(compiled_filename) = sandbox->filename;
  714. CG(zend_lineno) = 0;
  715. xc_sandbox_install(sandbox, install TSRMLS_CC);
  716. CG(in_compilation) = 0;
  717. CG(compiled_filename) = NULL;
  718. /* no free as it's installed */
  719. #ifdef HAVE_XCACHE_CONSTANT
  720. TG(zend_constants).pDestructor = NULL;
  721. #endif
  722. TG(function_table).pDestructor = NULL;
  723. TG(class_table).pDestructor = NULL;
  724. }
  725. /* destroy all the tmp */
  726. #ifdef HAVE_XCACHE_CONSTANT
  727. zend_hash_destroy(&TG(zend_constants));
  728. #endif
  729. zend_hash_destroy(&TG(function_table));
  730. zend_hash_destroy(&TG(class_table));
  731. #ifdef ZEND_ENGINE_2_1
  732. zend_hash_destroy(&TG(auto_globals));
  733. #endif
  734. zend_hash_destroy(TG(included_files));
  735. /* restore orig here, as EG/CG holded tmp before */
  736. memcpy(&EG(included_files), &OG(included_files), sizeof(EG(included_files)));
  737. #ifdef E_STRICT
  738. EG(user_error_handler_error_reporting) = sandbox->orig_user_error_handler_error_reporting;
  739. #endif
  740. #ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
  741. CG(compiler_options) = sandbox->orig_compiler_options;
  742. #endif
  743. if (sandbox->alloc) {
  744. efree(sandbox);
  745. }
  746. }
  747. /* }}} */
  748. int xc_vtrace(const char *fmt, va_list args) /* {{{ */
  749. {
  750. return vfprintf(stderr, fmt, args);
  751. }
  752. /* }}} */
  753. int xc_trace(const char *fmt, ...) /* {{{ */
  754. {
  755. va_list args;
  756. int ret;
  757. va_start(args, fmt);
  758. ret = xc_vtrace(fmt, args);
  759. va_end(args);
  760. return ret;
  761. }
  762. /* }}} */