1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
26 #include "php_psi_stdinc.h"
30 #include "ext/standard/info.h"
31 #include "zend_constants.h"
32 #include "zend_operators.h"
42 # define PSI_ENGINE "jit"
47 # define PSI_ENGINE "ffi"
50 ZEND_DECLARE_MODULE_GLOBALS(psi
);
52 //#define ZEND_INI_MH(name) int name(zend_ini_entry *entry, zend_string *new_value, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage)
54 static void OnUpdateBlacklist(const char *str
, void (*cb
)(const char*, size_t))
61 end
= strchr(str
, ',');
75 static void psi_blacklist_add_decl(const char *pattern
, size_t len
);
76 static ZEND_INI_MH(OnUpdateBlacklistedDecls
)
78 OnUpdateBlacklist(new_value
->val
, psi_blacklist_add_decl
);
82 static void psi_blacklist_add_var(const char *pattern
, size_t len
);
83 static ZEND_INI_MH(OnUpdateBlacklistedVars
)
85 OnUpdateBlacklist(new_value
->val
, psi_blacklist_add_var
);
89 static void OnDisplayBlacklist(struct psi_plist
*bl
)
94 while (psi_plist_get(bl
, i
++, &item
)) {
101 static ZEND_INI_DISP(OnDisplayBlacklistedDecls
)
103 OnDisplayBlacklist(PSI_G(blacklist
).decls
);
105 static ZEND_INI_DISP(OnDisplayBlacklistedVars
)
107 OnDisplayBlacklist(PSI_G(blacklist
).vars
);
111 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE
, PHP_INI_SYSTEM
, OnUpdateString
, engine
, zend_psi_globals
, psi_globals
)
112 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM
, OnUpdateString
, directory
, zend_psi_globals
, psi_globals
)
113 PHP_INI_ENTRY_EX("psi.blacklist.decls", "", PHP_INI_SYSTEM
, OnUpdateBlacklistedDecls
, OnDisplayBlacklistedDecls
)
114 PHP_INI_ENTRY_EX("psi.blacklist.vars", "", PHP_INI_SYSTEM
, OnUpdateBlacklistedVars
, OnDisplayBlacklistedVars
)
117 static zend_object_handlers psi_object_handlers
;
118 static zend_class_entry
*psi_class_entry
;
120 zend_class_entry
*psi_object_get_class_entry()
122 return psi_class_entry
;
125 static void psi_object_free(zend_object
*o
)
127 psi_object
*obj
= PSI_OBJ(NULL
, o
);
131 obj
->dtor(obj
->data
);
135 zend_object_std_dtor(o
);
138 zend_object
*psi_object_init_ex(zend_class_entry
*ce
, void *data
, void (*dtor
)(void *))
143 ce
= psi_class_entry
;
146 o
= ecalloc(1, sizeof(*o
) + zend_object_properties_size(ce
));
151 zend_object_std_init(&o
->std
, ce
);
152 object_properties_init(&o
->std
, ce
);
153 o
->std
.handlers
= &psi_object_handlers
;
157 zend_object
*psi_object_init(zend_class_entry
*ce
)
159 return psi_object_init_ex(ce
, NULL
, NULL
);
162 ZEND_BEGIN_ARG_INFO_EX(ai_psi_dump
, 0, 0, 0)
163 ZEND_ARG_INFO(0, stream
)
165 static PHP_FUNCTION(psi_dump
)
169 int fd
= STDOUT_FILENO
;
171 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &r
)) {
175 php_stream_from_zval(s
, r
);
177 if (SUCCESS
!= php_stream_cast(s
, PHP_STREAM_AS_FD
| PHP_STREAM_CAST_INTERNAL
, (void **)&fd
, 1)) {
181 psi_context_dump(PSI_G(context
), fd
);
184 ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate
, 0, 0, 1)
185 ZEND_ARG_INFO(0, file
)
186 ZEND_ARG_INFO(0, flags
)
187 ZEND_ARG_INFO(1, errcnt
)
189 static PHP_FUNCTION(psi_validate
)
192 struct psi_parser_input
*I
;
194 struct psi_data D
= {0};
195 struct psi_validate_scope S
= {0};
200 if (psi_check_env("PSI_DEBUG")) {
205 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS(), "P|lz", &file
, &flags
, &errcnt
)) {
209 if (!psi_parser_init(&P
, psi_error_wrapper
, flags
)) {
212 if (!(I
= psi_parser_open_file(&P
, file
->val
, true))) {
217 psi_parser_parse(&P
, I
);
218 psi_data_ctor(&D
, P
.error
, P
.flags
);
219 psi_validate_scope_ctor(&S
);
220 S
.defs
= &P
.preproc
->defs
;
222 RETVAL_BOOL(psi_validate(&S
, &D
, PSI_DATA(&P
)));
226 convert_to_long(errcnt
);
227 ZVAL_LONG(errcnt
, P
.errors
);
230 psi_validate_scope_dtor(&S
);
233 psi_parser_input_free(&I
);
236 ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate_string
, 0, 0, 1)
237 ZEND_ARG_INFO(0, string
)
238 ZEND_ARG_INFO(0, flags
)
239 ZEND_ARG_INFO(1, errcnt
)
241 static PHP_FUNCTION(psi_validate_string
)
244 struct psi_parser_input
*I
;
246 struct psi_data D
= {0};
247 struct psi_validate_scope S
= {0};
252 if (psi_check_env("PSI_DEBUG")) {
257 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS(), "S|lz", &string
, &flags
, &errcnt
)) {
261 if (!psi_parser_init(&P
, psi_error_wrapper
, flags
)) {
264 if (!(I
= psi_parser_open_string(&P
, string
->val
, string
->len
))) {
269 psi_parser_parse(&P
, I
);
270 psi_data_ctor(&D
, P
.error
, P
.flags
);
271 psi_validate_scope_ctor(&S
);
272 S
.defs
= &P
.preproc
->defs
;
274 RETVAL_BOOL(psi_validate(&S
, &D
, PSI_DATA(&P
)));
278 convert_to_long(errcnt
);
279 ZVAL_LONG(errcnt
, P
.errors
);
282 psi_validate_scope_dtor(&S
);
285 psi_parser_input_free(&I
);
288 PHP_MINIT_FUNCTION(psi_cpp
);
289 PHP_MINIT_FUNCTION(psi_context
);
290 static PHP_MINIT_FUNCTION(psi
)
292 zend_class_entry ce
= {0};
294 REGISTER_INI_ENTRIES();
296 zend_register_long_constant(ZEND_STRL("PSI_DEBUG"), PSI_DEBUG
, CONST_CS
|CONST_PERSISTENT
, module_number
);
297 zend_register_long_constant(ZEND_STRL("PSI_SILENT"), PSI_SILENT
, CONST_CS
|CONST_PERSISTENT
, module_number
);
299 INIT_NS_CLASS_ENTRY(ce
, "psi", "object", NULL
);
300 psi_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
301 psi_class_entry
->create_object
= psi_object_init
;
303 memcpy(&psi_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
304 psi_object_handlers
.offset
= XtOffsetOf(psi_object
, std
);
305 psi_object_handlers
.free_obj
= psi_object_free
;
306 psi_object_handlers
.clone_obj
= NULL
;
308 if (SUCCESS
!= PHP_MINIT(psi_cpp
)(type
, module_number
)) {
311 if (SUCCESS
!= PHP_MINIT(psi_context
)(type
, module_number
)) {
318 PHP_MSHUTDOWN_FUNCTION(psi_cpp
);
319 PHP_MSHUTDOWN_FUNCTION(psi_context
);
320 static PHP_MSHUTDOWN_FUNCTION(psi
)
322 PHP_MSHUTDOWN(psi_context
)(type
, module_number
);
323 PHP_MSHUTDOWN(psi_cpp
)(type
, module_number
);
325 UNREGISTER_INI_ENTRIES();
330 #if defined(COMPILE_DL_PSI) && defined(ZTS)
331 static PHP_RINIT_FUNCTION(psi
)
333 ZEND_TSRMLS_CACHE_UPDATE();
338 static PHP_MINFO_FUNCTION(psi
)
340 php_info_print_table_start();
341 php_info_print_table_header(2, "PSI Support", "enabled");
342 php_info_print_table_row(2, "Extension Version", PHP_PSI_VERSION
);
343 php_info_print_table_row(2, "Search Path", PSI_G(search_path
));
344 php_info_print_table_end();
346 php_info_print_table_start();
347 php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
348 php_info_print_table_row(3, "libffi",
349 #ifndef PHP_PSI_LIBFFI_VERSION
350 # define PHP_PSI_LIBFFI_VERSION "unknown"
353 PHP_PSI_LIBFFI_VERSION
, "unknown"
355 "disabled", "disabled"
358 php_info_print_table_row(3, "libjit",
362 "disabled", "disabled"
366 DISPLAY_INI_ENTRIES();
369 static void ptr_free(void *ptr
)
371 free(*(void **) ptr
);
374 static void psi_blacklist_add_decl(const char *pattern
, size_t len
)
376 char *tmp
= strndup(pattern
, len
);
377 struct psi_plist
**decls
= &PSI_G(blacklist
).decls
;
379 *decls
= psi_plist_add(*decls
, &tmp
);
382 static void psi_blacklist_add_var(const char *pattern
, size_t len
)
384 char *tmp
= strndup(pattern
, len
);
385 struct psi_plist
**vars
= &PSI_G(blacklist
).vars
;
387 *vars
= psi_plist_add(*vars
, &tmp
);
390 static PHP_GINIT_FUNCTION(psi
)
393 struct psi_plist
**bl_decls
= &psi_globals
->blacklist
.decls
;
394 struct psi_plist
**bl_vars
= &psi_globals
->blacklist
.vars
;
396 *bl_decls
= psi_plist_init(ptr_free
);
397 *bl_vars
= psi_plist_init(ptr_free
);
399 #define BL_ADD(D, d) \
401 *D = psi_plist_add(*D, &tmp)
402 #define BL_DECL_ADD(d) BL_ADD(bl_decls, d)
403 #define BL_VAR_ADD(d) BL_ADD(bl_vars, d)
405 BL_DECL_ADD("dlsym");
406 BL_DECL_ADD("alloca");
407 BL_DECL_ADD("atexit");
408 BL_DECL_ADD("at_quick_exit");
411 BL_DECL_ADD("_IO_cookie_init");
412 BL_DECL_ADD("bindresvport6");
415 BL_DECL_ADD("*v*printf");
416 BL_DECL_ADD("*v*scanf");
417 BL_DECL_ADD("vsyslog");
419 /* LFS/LFO for 32bit */
420 BL_DECL_ADD("*stat*64");
421 BL_DECL_ADD("*glob*64");
423 BL_DECL_ADD("getumask");
425 /* using hidden structs */
426 BL_VAR_ADD("_IO_2_*");
429 static PHP_GSHUTDOWN_FUNCTION(psi
)
431 psi_plist_free(psi_globals
->blacklist
.decls
);
434 static const zend_function_entry psi_functions
[] = {
435 PHP_FE(psi_dump
, ai_psi_dump
)
436 PHP_FE(psi_validate
, ai_psi_validate
)
437 PHP_FE(psi_validate_string
, ai_psi_validate_string
)
441 static const zend_module_dep psi_deps
[] = {
442 ZEND_MOD_REQUIRED("standard")
446 zend_module_entry psi_module_entry
= {
447 STANDARD_MODULE_HEADER_EX
,
454 #if defined(COMPILE_DL_PSI) && defined(ZTS)
455 PHP_RINIT(psi
), /* Replace with NULL if there's nothing to do at request start */
462 ZEND_MODULE_GLOBALS(psi
),
465 NULL
, /* post-deactivate */
466 STANDARD_MODULE_PROPERTIES_EX
469 #ifdef COMPILE_DL_PSI
471 ZEND_TSRMLS_CACHE_DEFINE();
481 * vim600: noet sw=4 ts=4 fdm=marker
482 * vim<600: noet sw=4 ts=4