assert.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Thies C. Arntzen <thies@thieso.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. /* {{{ includes */
  20. #include "php.h"
  21. #include "php_assert.h"
  22. #include "php_ini.h"
  23. /* }}} */
  24. ZEND_BEGIN_MODULE_GLOBALS(assert)
  25. long active;
  26. long bail;
  27. long warning;
  28. long quiet_eval;
  29. zval *callback;
  30. char *cb;
  31. ZEND_END_MODULE_GLOBALS(assert)
  32. ZEND_DECLARE_MODULE_GLOBALS(assert)
  33. #ifdef ZTS
  34. #define ASSERTG(v) TSRMG(assert_globals_id, zend_assert_globals *, v)
  35. #else
  36. #define ASSERTG(v) (assert_globals.v)
  37. #endif
  38. #define SAFE_STRING(s) ((s)?(s):"")
  39. enum {
  40. ASSERT_ACTIVE=1,
  41. ASSERT_CALLBACK,
  42. ASSERT_BAIL,
  43. ASSERT_WARNING,
  44. ASSERT_QUIET_EVAL
  45. };
  46. static PHP_INI_MH(OnChangeCallback) /* {{{ */
  47. {
  48. if (EG(in_execution)) {
  49. if (ASSERTG(callback)) {
  50. zval_ptr_dtor(&ASSERTG(callback));
  51. ASSERTG(callback) = NULL;
  52. }
  53. if (new_value && (ASSERTG(callback) || new_value_length)) {
  54. MAKE_STD_ZVAL(ASSERTG(callback));
  55. ZVAL_STRINGL(ASSERTG(callback), new_value, new_value_length, 1);
  56. }
  57. } else {
  58. if (ASSERTG(cb)) {
  59. pefree(ASSERTG(cb), 1);
  60. }
  61. if (new_value && new_value_length) {
  62. ASSERTG(cb) = pemalloc(new_value_length + 1, 1);
  63. memcpy(ASSERTG(cb), new_value, new_value_length);
  64. ASSERTG(cb)[new_value_length] = '\0';
  65. } else {
  66. ASSERTG(cb) = NULL;
  67. }
  68. }
  69. return SUCCESS;
  70. }
  71. /* }}} */
  72. PHP_INI_BEGIN()
  73. STD_PHP_INI_ENTRY("assert.active", "1", PHP_INI_ALL, OnUpdateLong, active, zend_assert_globals, assert_globals)
  74. STD_PHP_INI_ENTRY("assert.bail", "0", PHP_INI_ALL, OnUpdateLong, bail, zend_assert_globals, assert_globals)
  75. STD_PHP_INI_ENTRY("assert.warning", "1", PHP_INI_ALL, OnUpdateLong, warning, zend_assert_globals, assert_globals)
  76. PHP_INI_ENTRY("assert.callback", NULL, PHP_INI_ALL, OnChangeCallback)
  77. STD_PHP_INI_ENTRY("assert.quiet_eval", "0", PHP_INI_ALL, OnUpdateLong, quiet_eval, zend_assert_globals, assert_globals)
  78. PHP_INI_END()
  79. static void php_assert_init_globals(zend_assert_globals *assert_globals_p TSRMLS_DC) /* {{{ */
  80. {
  81. assert_globals_p->callback = NULL;
  82. assert_globals_p->cb = NULL;
  83. }
  84. /* }}} */
  85. PHP_MINIT_FUNCTION(assert) /* {{{ */
  86. {
  87. ZEND_INIT_MODULE_GLOBALS(assert, php_assert_init_globals, NULL);
  88. REGISTER_INI_ENTRIES();
  89. REGISTER_LONG_CONSTANT("ASSERT_ACTIVE", ASSERT_ACTIVE, CONST_CS|CONST_PERSISTENT);
  90. REGISTER_LONG_CONSTANT("ASSERT_CALLBACK", ASSERT_CALLBACK, CONST_CS|CONST_PERSISTENT);
  91. REGISTER_LONG_CONSTANT("ASSERT_BAIL", ASSERT_BAIL, CONST_CS|CONST_PERSISTENT);
  92. REGISTER_LONG_CONSTANT("ASSERT_WARNING", ASSERT_WARNING, CONST_CS|CONST_PERSISTENT);
  93. REGISTER_LONG_CONSTANT("ASSERT_QUIET_EVAL", ASSERT_QUIET_EVAL, CONST_CS|CONST_PERSISTENT);
  94. return SUCCESS;
  95. }
  96. /* }}} */
  97. PHP_MSHUTDOWN_FUNCTION(assert) /* {{{ */
  98. {
  99. if (ASSERTG(cb)) {
  100. pefree(ASSERTG(cb), 1);
  101. ASSERTG(cb) = NULL;
  102. }
  103. return SUCCESS;
  104. }
  105. /* }}} */
  106. PHP_RSHUTDOWN_FUNCTION(assert) /* {{{ */
  107. {
  108. if (ASSERTG(callback)) {
  109. zval_ptr_dtor(&ASSERTG(callback));
  110. ASSERTG(callback) = NULL;
  111. }
  112. return SUCCESS;
  113. }
  114. /* }}} */
  115. PHP_MINFO_FUNCTION(assert) /* {{{ */
  116. {
  117. DISPLAY_INI_ENTRIES();
  118. }
  119. /* }}} */
  120. /* {{{ proto int assert(string|bool assertion[, string description])
  121. Checks if assertion is false */
  122. PHP_FUNCTION(assert)
  123. {
  124. zval **assertion;
  125. int val, description_len = 0;
  126. char *myeval = NULL;
  127. char *compiled_string_description, *description = NULL;
  128. if (! ASSERTG(active)) {
  129. RETURN_TRUE;
  130. }
  131. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s", &assertion, &description, &description_len) == FAILURE) {
  132. return;
  133. }
  134. if (Z_TYPE_PP(assertion) == IS_STRING) {
  135. zval retval;
  136. int old_error_reporting = 0; /* shut up gcc! */
  137. myeval = Z_STRVAL_PP(assertion);
  138. if (ASSERTG(quiet_eval)) {
  139. old_error_reporting = EG(error_reporting);
  140. EG(error_reporting) = 0;
  141. }
  142. compiled_string_description = zend_make_compiled_string_description("assert code" TSRMLS_CC);
  143. if (zend_eval_stringl(myeval, Z_STRLEN_PP(assertion), &retval, compiled_string_description TSRMLS_CC) == FAILURE) {
  144. efree(compiled_string_description);
  145. if (description_len == 0) {
  146. php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Failure evaluating code: %s%s", PHP_EOL, myeval);
  147. } else {
  148. php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Failure evaluating code: %s%s:\"%s\"", PHP_EOL, description, myeval);
  149. }
  150. if (ASSERTG(bail)) {
  151. zend_bailout();
  152. }
  153. RETURN_FALSE;
  154. }
  155. efree(compiled_string_description);
  156. if (ASSERTG(quiet_eval)) {
  157. EG(error_reporting) = old_error_reporting;
  158. }
  159. convert_to_boolean(&retval);
  160. val = Z_LVAL(retval);
  161. } else {
  162. convert_to_boolean_ex(assertion);
  163. val = Z_LVAL_PP(assertion);
  164. }
  165. if (val) {
  166. RETURN_TRUE;
  167. }
  168. if (!ASSERTG(callback) && ASSERTG(cb)) {
  169. MAKE_STD_ZVAL(ASSERTG(callback));
  170. ZVAL_STRING(ASSERTG(callback), ASSERTG(cb), 1);
  171. }
  172. if (ASSERTG(callback)) {
  173. zval **args = safe_emalloc(description_len == 0 ? 3 : 4, sizeof(zval *), 0);
  174. zval *retval;
  175. int i;
  176. uint lineno = zend_get_executed_lineno(TSRMLS_C);
  177. const char *filename = zend_get_executed_filename(TSRMLS_C);
  178. MAKE_STD_ZVAL(args[0]);
  179. MAKE_STD_ZVAL(args[1]);
  180. MAKE_STD_ZVAL(args[2]);
  181. ZVAL_STRING(args[0], SAFE_STRING(filename), 1);
  182. ZVAL_LONG (args[1], lineno);
  183. ZVAL_STRING(args[2], SAFE_STRING(myeval), 1);
  184. MAKE_STD_ZVAL(retval);
  185. ZVAL_FALSE(retval);
  186. /* XXX do we want to check for error here? */
  187. if (description_len == 0) {
  188. call_user_function(CG(function_table), NULL, ASSERTG(callback), retval, 3, args TSRMLS_CC);
  189. for (i = 0; i <= 2; i++) {
  190. zval_ptr_dtor(&(args[i]));
  191. }
  192. } else {
  193. MAKE_STD_ZVAL(args[3]);
  194. ZVAL_STRINGL(args[3], SAFE_STRING(description), description_len, 1);
  195. call_user_function(CG(function_table), NULL, ASSERTG(callback), retval, 4, args TSRMLS_CC);
  196. for (i = 0; i <= 3; i++) {
  197. zval_ptr_dtor(&(args[i]));
  198. }
  199. }
  200. efree(args);
  201. zval_ptr_dtor(&retval);
  202. }
  203. if (ASSERTG(warning)) {
  204. if (description_len == 0) {
  205. if (myeval) {
  206. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Assertion \"%s\" failed", myeval);
  207. } else {
  208. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Assertion failed");
  209. }
  210. } else {
  211. if (myeval) {
  212. php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: \"%s\" failed", description, myeval);
  213. } else {
  214. php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s failed", description);
  215. }
  216. }
  217. }
  218. if (ASSERTG(bail)) {
  219. zend_bailout();
  220. }
  221. }
  222. /* }}} */
  223. /* {{{ proto mixed assert_options(int what [, mixed value])
  224. Set/get the various assert flags */
  225. PHP_FUNCTION(assert_options)
  226. {
  227. zval **value = NULL;
  228. long what;
  229. int oldint;
  230. int ac = ZEND_NUM_ARGS();
  231. if (zend_parse_parameters(ac TSRMLS_CC, "l|Z", &what, &value) == FAILURE) {
  232. return;
  233. }
  234. switch (what) {
  235. case ASSERT_ACTIVE:
  236. oldint = ASSERTG(active);
  237. if (ac == 2) {
  238. convert_to_string_ex(value);
  239. zend_alter_ini_entry_ex("assert.active", sizeof("assert.active"), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
  240. }
  241. RETURN_LONG(oldint);
  242. break;
  243. case ASSERT_BAIL:
  244. oldint = ASSERTG(bail);
  245. if (ac == 2) {
  246. convert_to_string_ex(value);
  247. zend_alter_ini_entry_ex("assert.bail", sizeof("assert.bail"), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
  248. }
  249. RETURN_LONG(oldint);
  250. break;
  251. case ASSERT_QUIET_EVAL:
  252. oldint = ASSERTG(quiet_eval);
  253. if (ac == 2) {
  254. convert_to_string_ex(value);
  255. zend_alter_ini_entry_ex("assert.quiet_eval", sizeof("assert.quiet_eval"), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
  256. }
  257. RETURN_LONG(oldint);
  258. break;
  259. case ASSERT_WARNING:
  260. oldint = ASSERTG(warning);
  261. if (ac == 2) {
  262. convert_to_string_ex(value);
  263. zend_alter_ini_entry_ex("assert.warning", sizeof("assert.warning"), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
  264. }
  265. RETURN_LONG(oldint);
  266. break;
  267. case ASSERT_CALLBACK:
  268. if (ASSERTG(callback) != NULL) {
  269. RETVAL_ZVAL(ASSERTG(callback), 1, 0);
  270. } else if (ASSERTG(cb)) {
  271. RETVAL_STRING(ASSERTG(cb), 1);
  272. } else {
  273. RETVAL_NULL();
  274. }
  275. if (ac == 2) {
  276. if (ASSERTG(callback)) {
  277. zval_ptr_dtor(&ASSERTG(callback));
  278. }
  279. ASSERTG(callback) = *value;
  280. zval_add_ref(value);
  281. }
  282. return;
  283. break;
  284. default:
  285. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown value %ld", what);
  286. break;
  287. }
  288. RETURN_FALSE;
  289. }
  290. /* }}} */
  291. /*
  292. * Local variables:
  293. * tab-width: 4
  294. * c-basic-offset: 4
  295. * End:
  296. * vim600: sw=4 ts=4 fdm=marker
  297. * vim<600: sw=4 ts=4
  298. */