build administrativa
[m6w6/ext-psi] / src / module.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
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.
13
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 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31
32 #include "php.h"
33 #include "php_ini.h"
34 #include "ext/standard/info.h"
35 #include "zend_constants.h"
36 #include "zend_operators.h"
37
38 #include "php_psi.h"
39 #include "token.h"
40 #include "parser.h"
41 #include "cpp.h"
42
43 #if HAVE_LIBJIT
44 # include "libjit.h"
45 # ifndef HAVE_LIBFFI
46 # define PSI_ENGINE "jit"
47 # endif
48 #endif
49 #if HAVE_LIBFFI
50 # include "libffi.h"
51 # define PSI_ENGINE "ffi"
52 #endif
53
54 ZEND_DECLARE_MODULE_GLOBALS(psi);
55
56 //#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)
57
58 static void OnUpdateBlacklist(const char *str, void (*cb)(const char*, size_t))
59 {
60 const char *end;
61
62 do {
63 size_t len;
64
65 end = strchr(str, ',');
66 if (end) {
67 len = end - str;
68 } else {
69 len = strlen(str);
70 }
71 if (len) {
72 cb(str, len);
73 }
74
75 str = end + 1;
76 } while (end);
77 }
78
79 static void psi_blacklist_add_decl(const char *pattern, size_t len);
80 static ZEND_INI_MH(OnUpdateBlacklistedDecls)
81 {
82 OnUpdateBlacklist(new_value->val, psi_blacklist_add_decl);
83 return SUCCESS;
84 }
85
86 static void psi_blacklist_add_var(const char *pattern, size_t len);
87 static ZEND_INI_MH(OnUpdateBlacklistedVars)
88 {
89 OnUpdateBlacklist(new_value->val, psi_blacklist_add_var);
90 return SUCCESS;
91 }
92
93 static void OnDisplayBlacklist(struct psi_plist *bl)
94 {
95 size_t i = 0;
96 char *item;
97
98 while (psi_plist_get(bl, i++, &item)) {
99 if (i > 1) {
100 PUTS(",");
101 }
102 PUTS(item);
103 }
104 }
105 static ZEND_INI_DISP(OnDisplayBlacklistedDecls)
106 {
107 OnDisplayBlacklist(PSI_G(blacklist).decls);
108 }
109 static ZEND_INI_DISP(OnDisplayBlacklistedVars)
110 {
111 OnDisplayBlacklist(PSI_G(blacklist).vars);
112 }
113
114 PHP_INI_BEGIN()
115 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE, PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
116 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
117 PHP_INI_ENTRY_EX("psi.blacklist.decls", "", PHP_INI_SYSTEM, OnUpdateBlacklistedDecls, OnDisplayBlacklistedDecls)
118 PHP_INI_ENTRY_EX("psi.blacklist.vars", "", PHP_INI_SYSTEM, OnUpdateBlacklistedVars, OnDisplayBlacklistedVars)
119 PHP_INI_END();
120
121 static zend_object_handlers psi_object_handlers;
122 static zend_class_entry *psi_class_entry;
123
124 zend_class_entry *psi_object_get_class_entry()
125 {
126 return psi_class_entry;
127 }
128
129 static void psi_object_free(zend_object *o)
130 {
131 psi_object *obj = PSI_OBJ(NULL, o);
132
133 if (obj->data) {
134 if (obj->dtor) {
135 obj->dtor(obj->data);
136 }
137 obj->data = NULL;
138 }
139 zend_object_std_dtor(o);
140 }
141
142 zend_object *psi_object_init_ex(zend_class_entry *ce, void *data, void (*dtor)(void *))
143 {
144 psi_object *o;
145
146 if (!ce) {
147 ce = psi_class_entry;
148 }
149
150 o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
151
152 o->data = data;
153 o->dtor = dtor;
154
155 zend_object_std_init(&o->std, ce);
156 object_properties_init(&o->std, ce);
157 o->std.handlers = &psi_object_handlers;
158 return &o->std;
159 }
160
161 zend_object *psi_object_init(zend_class_entry *ce)
162 {
163 return psi_object_init_ex(ce, NULL, NULL);
164 }
165
166 ZEND_BEGIN_ARG_INFO_EX(ai_psi_dump, 0, 0, 0)
167 ZEND_ARG_INFO(0, stream)
168 ZEND_END_ARG_INFO();
169 static PHP_FUNCTION(psi_dump)
170 {
171 php_stream *s;
172 zval *r = NULL;
173 struct psi_dump dump = {.fun = (psi_dump_cb) php_stream_printf};
174
175 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &r)) {
176 return;
177 }
178 if (r) {
179 php_stream_from_zval(s, r);
180 dump.ctx.hn = s;
181 } else {
182 dump.ctx.hn = php_stream_open_wrapper("php://output", "w", REPORT_ERRORS, NULL);
183 }
184 psi_context_dump(&dump, PSI_G(context));
185 }
186
187 ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate, 0, 0, 1)
188 ZEND_ARG_INFO(0, file)
189 ZEND_ARG_INFO(0, flags)
190 ZEND_ARG_INFO(1, errcnt)
191 ZEND_END_ARG_INFO();
192 static PHP_FUNCTION(psi_validate)
193 {
194 zend_string *file;
195 struct psi_parser_input *I;
196 struct psi_parser P;
197 struct psi_data D = {0};
198 struct psi_validate_scope S = {0};
199 zend_long flags = 0;
200 zval *errcnt = NULL;
201
202 #if PHP_DEBUG
203 if (psi_check_env("PSI_DEBUG")) {
204 flags |= PSI_DEBUG;
205 }
206 #endif
207
208 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "P|lz", &file, &flags, &errcnt)) {
209 return;
210 }
211
212 if (!psi_parser_init(&P, psi_error_wrapper, flags)) {
213 RETURN_FALSE;
214 }
215 if (!(I = psi_parser_open_file(&P, file->val, true))) {
216 psi_parser_dtor(&P);
217 RETURN_FALSE;
218 }
219
220 psi_parser_parse(&P, I);
221 psi_data_ctor(&D, P.error, P.flags);
222 psi_validate_scope_ctor(&S);
223 S.cpp = P.preproc;
224
225 RETVAL_BOOL(psi_validate(&S, &D, PSI_DATA(&P)));
226
227 if (errcnt) {
228 ZVAL_DEREF(errcnt);
229 convert_to_long(errcnt);
230 ZVAL_LONG(errcnt, P.errors);
231 }
232
233 psi_validate_scope_dtor(&S);
234 psi_data_dtor(&D);
235 psi_parser_dtor(&P);
236 psi_parser_input_free(&I);
237 }
238
239 ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate_string, 0, 0, 1)
240 ZEND_ARG_INFO(0, string)
241 ZEND_ARG_INFO(0, flags)
242 ZEND_ARG_INFO(1, errcnt)
243 ZEND_END_ARG_INFO();
244 static PHP_FUNCTION(psi_validate_string)
245 {
246 zend_string *string;
247 struct psi_parser_input *I;
248 struct psi_parser P;
249 struct psi_data D = {0};
250 struct psi_validate_scope S = {0};
251 zend_long flags = 0;
252 zval *errcnt = NULL;
253
254 #if PHP_DEBUG
255 if (psi_check_env("PSI_DEBUG")) {
256 flags |= PSI_DEBUG;
257 }
258 #endif
259
260 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S|lz", &string, &flags, &errcnt)) {
261 return;
262 }
263
264 if (!psi_parser_init(&P, psi_error_wrapper, flags)) {
265 RETURN_FALSE;
266 }
267 if (!(I = psi_parser_open_string(&P, string->val, string->len))) {
268 psi_parser_dtor(&P);
269 RETURN_FALSE;
270 }
271
272 psi_parser_parse(&P, I);
273 psi_data_ctor(&D, P.error, P.flags);
274 psi_validate_scope_ctor(&S);
275 S.cpp = P.preproc;
276
277 RETVAL_BOOL(psi_validate(&S, &D, PSI_DATA(&P)));
278
279 if (errcnt) {
280 ZVAL_DEREF(errcnt);
281 convert_to_long(errcnt);
282 ZVAL_LONG(errcnt, P.errors);
283 }
284
285 psi_validate_scope_dtor(&S);
286 psi_data_dtor(&D);
287 psi_parser_dtor(&P);
288 psi_parser_input_free(&I);
289 }
290
291 PHP_MINIT_FUNCTION(psi_cpp);
292 PHP_MINIT_FUNCTION(psi_builtin);
293 PHP_MINIT_FUNCTION(psi_context);
294 static PHP_MINIT_FUNCTION(psi)
295 {
296 zend_class_entry ce = {0};
297
298 REGISTER_INI_ENTRIES();
299
300 zend_register_long_constant(ZEND_STRL("PSI_DEBUG"), PSI_DEBUG, CONST_CS|CONST_PERSISTENT, module_number);
301 zend_register_long_constant(ZEND_STRL("PSI_SILENT"), PSI_SILENT, CONST_CS|CONST_PERSISTENT, module_number);
302
303 INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
304 psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
305 psi_class_entry->create_object = psi_object_init;
306
307 memcpy(&psi_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
308 psi_object_handlers.offset = XtOffsetOf(psi_object, std);
309 psi_object_handlers.free_obj = psi_object_free;
310 psi_object_handlers.clone_obj = NULL;
311
312 if (SUCCESS != PHP_MINIT(psi_builtin)(type, module_number)) {
313 return FAILURE;
314 }
315 if (SUCCESS != PHP_MINIT(psi_cpp)(type, module_number)) {
316 return FAILURE;
317 }
318 if (SUCCESS != PHP_MINIT(psi_context)(type, module_number)) {
319 return FAILURE;
320 }
321
322 return SUCCESS;
323 }
324
325 PHP_MSHUTDOWN_FUNCTION(psi_cpp);
326 PHP_MSHUTDOWN_FUNCTION(psi_builtin);
327 PHP_MSHUTDOWN_FUNCTION(psi_context);
328 static PHP_MSHUTDOWN_FUNCTION(psi)
329 {
330 PHP_MSHUTDOWN(psi_context)(type, module_number);
331 PHP_MSHUTDOWN(psi_cpp)(type, module_number);
332 PHP_MSHUTDOWN(psi_builtin)(type, module_number);
333
334 UNREGISTER_INI_ENTRIES();
335
336 return SUCCESS;
337 }
338
339 #if defined(COMPILE_DL_PSI) && defined(ZTS)
340 static PHP_RINIT_FUNCTION(psi)
341 {
342 ZEND_TSRMLS_CACHE_UPDATE();
343 return SUCCESS;
344 }
345 #endif
346
347 static PHP_MINFO_FUNCTION(psi)
348 {
349 php_info_print_table_start();
350 php_info_print_table_header(2, "PSI Support", "enabled");
351 php_info_print_table_row(2, "Extension Version", PHP_PSI_VERSION);
352 php_info_print_table_row(2, "Search Path", PSI_G(search_path));
353 php_info_print_table_end();
354
355 php_info_print_table_start();
356 php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
357 php_info_print_table_row(3, "libffi",
358 #ifndef PHP_PSI_LIBFFI_VERSION
359 # define PHP_PSI_LIBFFI_VERSION "unknown"
360 #endif
361 #ifdef HAVE_LIBFFI
362 PHP_PSI_LIBFFI_VERSION, "unknown"
363 #else
364 "disabled", "disabled"
365 #endif
366 );
367 php_info_print_table_row(3, "libjit",
368 #ifdef HAVE_LIBJIT
369 "unknown", "unknown"
370 #else
371 "disabled", "disabled"
372 #endif
373 );
374
375 DISPLAY_INI_ENTRIES();
376 }
377
378 static void ptr_free(void *ptr)
379 {
380 free(*(void **) ptr);
381 }
382
383 static void psi_blacklist_add_decl(const char *pattern, size_t len)
384 {
385 char *tmp = strndup(pattern, len);
386 struct psi_plist **decls = &PSI_G(blacklist).decls;
387
388 *decls = psi_plist_add(*decls, &tmp);
389 }
390
391 static void psi_blacklist_add_var(const char *pattern, size_t len)
392 {
393 char *tmp = strndup(pattern, len);
394 struct psi_plist **vars = &PSI_G(blacklist).vars;
395
396 *vars = psi_plist_add(*vars, &tmp);
397 }
398
399 static PHP_GINIT_FUNCTION(psi)
400 {
401 char *tmp;
402 struct psi_plist **bl_decls = &psi_globals->blacklist.decls;
403 struct psi_plist **bl_vars = &psi_globals->blacklist.vars;
404
405 *bl_decls = psi_plist_init(ptr_free);
406 *bl_vars = psi_plist_init(ptr_free);
407
408 #define BL_ADD(D, d) \
409 tmp = strdup(d); \
410 *D = psi_plist_add(*D, &tmp)
411 #define BL_DECL_ADD(d) BL_ADD(bl_decls, d)
412 #define BL_VAR_ADD(d) BL_ADD(bl_vars, d)
413
414 BL_DECL_ADD("dlsym");
415 BL_DECL_ADD("alloca");
416 BL_DECL_ADD("atexit");
417 BL_DECL_ADD("at_quick_exit");
418
419 /* missing */
420 BL_DECL_ADD("_IO_cookie_init");
421 BL_DECL_ADD("bindresvport6");
422
423 /* va_list as arg */
424 BL_DECL_ADD("*v*printf");
425 BL_DECL_ADD("*v*scanf");
426 BL_DECL_ADD("vsyslog");
427
428 /* LFS/LFO for 32bit */
429 BL_DECL_ADD("*stat*64");
430 BL_DECL_ADD("*glob*64");
431 /* Hurd only */
432 BL_DECL_ADD("getumask");
433
434 /* using hidden structs */
435 BL_VAR_ADD("_IO_2_*");
436 }
437
438 static PHP_GSHUTDOWN_FUNCTION(psi)
439 {
440 psi_plist_free(psi_globals->blacklist.decls);
441 }
442
443 static const zend_function_entry psi_functions[] = {
444 PHP_FE(psi_dump, ai_psi_dump)
445 PHP_FE(psi_validate, ai_psi_validate)
446 PHP_FE(psi_validate_string, ai_psi_validate_string)
447 PHP_FE_END
448 };
449
450 static const zend_module_dep psi_deps[] = {
451 ZEND_MOD_REQUIRED("standard")
452 {0}
453 };
454
455 zend_module_entry psi_module_entry = {
456 STANDARD_MODULE_HEADER_EX,
457 NULL,
458 psi_deps,
459 "psi",
460 psi_functions,
461 PHP_MINIT(psi),
462 PHP_MSHUTDOWN(psi),
463 #if defined(COMPILE_DL_PSI) && defined(ZTS)
464 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
465 #else
466 NULL,
467 #endif
468 NULL,
469 PHP_MINFO(psi),
470 PHP_PSI_VERSION,
471 ZEND_MODULE_GLOBALS(psi),
472 PHP_GINIT(psi),
473 PHP_GSHUTDOWN(psi),
474 NULL, /* post-deactivate */
475 STANDARD_MODULE_PROPERTIES_EX
476 };
477
478 #ifdef COMPILE_DL_PSI
479 #ifdef ZTS
480 ZEND_TSRMLS_CACHE_DEFINE();
481 #endif
482 ZEND_GET_MODULE(psi)
483 #endif
484
485 /*
486 * Local variables:
487 * tab-width: 4
488 * c-basic-offset: 4
489 * End:
490 * vim600: noet sw=4 ts=4 fdm=marker
491 * vim<600: noet sw=4 ts=4
492 */