PHP extensions • Internal data structures • Navigating PHP’s source • Executing a PHP file • Opcodes, caching, and optimization • Examining how PHP interacts with C • Debugging crashes
concepts to be added to PHP ◦ Integration with C, system libraries ◦ e.g. APCu, MongoDB, OpenSSL • Zend Extensions ◦ More hooks for changing PHP’s behavior ◦ Commonly used for debuggers and profilers ◦ May also register normal extensions for user APIs ◦ e.g. OPCache, Xdebug, phpdbg, Blackfire
zero ◦ Requests access globals via TSRM macros ◦ Zend hash globals can be used as a cache • Process model ◦ GINIT is called once, before MINIT ◦ GSHUTDOWN is called once, during MSHUTDOWN • Thread model ◦ Additionally called each time a thread spawns or dies ◦ TSRM macros take care of thread local storage
of PHP processes (CLI) • Bootstraps application once per worker process • Each worker handles a series of HTTP requests • Leverages request/response design in frameworks • Operates entirely within one CLI “request” • Issues with memory leaks, resetting state
value (8-bytes) ◦ Integer and double values are stored inline ◦ Pointers are used for other types (e.g. string, array, object) ◦ Not used for null and boolean values (denoted by type_info) • u1 contains type_info (4-bytes) ◦ Type byte and various bit flags • u2 is a multi-purpose union (4-bytes) ◦ Used for hash tables, AST line numbers, foreach iteration, etc.
individually heap-allocated ◦ Can now be directly embedded (e.g. hash buckets) • Zvals are no longer refcounted ◦ Refcounts stored on values themselves (e.g. zend_string) ◦ Values can be shared independently of the zval struct • Much less indirection and pointer traversal
and write files, sockets, devices • fork, exec, or wait on another process • exit the current process • Send signals to other processes (kill) • Map files or devices to memory (mmap, munmap) • Allocate process memory (brk, sbrk)
◦ C makes it trivially easy to access memory incorrectly • Ideally, crashes produce core dumps, which can be inspected ◦ https://bugs.php.net/bugs-generating-backtrace.php • PHP source includes a .gdbinit file with helpful macros
Reading symbols from php...done. (gdb) run Starting program: /usr/bin/php class-tostring-recursion.php Program received signal SIGSEGV, Segmentation fault. 0x0000555555c9ab9e in zend_call_function (fci=<error reading variable: Cannot access memory at address 0x7fffff7fef78>, fci_cache=<error reading variable: Cannot access memory at address 0x7fffff7fef70>) at /tmp/build_php-7.2.6.sx8/php-7.2.6/Zend/zend_execute_API.c:659 (gdb)
(object=0x7ffff3423110, #45994 0x0000555555d13de3 in zend_std_cast_object_tostring (readobj=0x #45995 0x0000555555ca5c8f in _zval_get_string_func (op=0x7ffff3423110) #45996 0x0000555555cb4b68 in zend_make_printable_zval (expr=0x7ffff342 #45997 0x0000555555cae0a8 in concat_function (result=0x7ffff3423120, o #45998 0x0000555555d4069a in ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDLER () #45999 0x0000555555db6336 in execute_ex (ex=0x7ffff34230c0) at /tmp/bu #46000 0x0000555555c9b9e1 in zend_call_function (fci=0x7fffffffb0b0, f #46001 0x0000555555ce6e8a in zend_call_method (object=0x7ffff3423090, #46002 0x0000555555d13de3 in zend_std_cast_object_tostring (readobj=0x #46003 0x0000555555ca5c8f in _zval_get_string_func (op=0x7ffff3423090)
zend_call_function (fci=0x7fffffffb0b0, f #46001 0x0000555555ce6e8a in zend_call_method (object=0x7ffff3423090, #46002 0x0000555555d13de3 in zend_std_cast_object_tostring (readobj=0x #46003 0x0000555555ca5c8f in _zval_get_string_func (op=0x7ffff3423090) #46004 0x0000555555cb4b68 in zend_make_printable_zval (expr=0x7ffff342 #46005 0x0000555555cae0a8 in concat_function (result=0x7ffff34230b0, o #46006 0x0000555555d4069a in ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDLER () #46007 0x0000555555db6336 in execute_ex (ex=0x7ffff3423030) at /tmp/bu #46008 0x0000555555dbaa7d in zend_execute (op_array=0x7ffff3489300, re #46009 0x0000555555cb8f1e in zend_execute_scripts (type=8, retval=0x0, #46010 0x0000555555befaa9 in php_execute_script (primary_file=0x7fffff #46011 0x0000555555dbd88f in do_cli (argc=2, argv=0x5555568f9380) at / #46012 0x0000555555dbed26 in main (argc=2, argv=0x5555568f9380) at /tm