Coverage Report

Created: 2023-06-24 09:56

/src/php-src/ext/standard/assert.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright (c) The PHP Group                                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to version 3.01 of the PHP license,      |
6
   | that is bundled with this package in the file LICENSE, and is        |
7
   | available through the world-wide-web at the following url:           |
8
   | https://www.php.net/license/3_01.txt                                 |
9
   | If you did not receive a copy of the PHP license and are unable to   |
10
   | obtain it through the world-wide-web, please send a note to          |
11
   | license@php.net so we can mail you a copy immediately.               |
12
   +----------------------------------------------------------------------+
13
   | Author: Thies C. Arntzen <thies@thieso.net>                          |
14
   +----------------------------------------------------------------------+
15
*/
16
17
/* {{{ includes */
18
#include "php.h"
19
#include "php_assert.h"
20
#include "php_ini.h"
21
#include "zend_exceptions.h"
22
/* }}} */
23
24
ZEND_BEGIN_MODULE_GLOBALS(assert)
25
  zval callback;
26
  char *cb;
27
  bool active;
28
  bool bail;
29
  bool warning;
30
  bool exception;
31
ZEND_END_MODULE_GLOBALS(assert)
32
33
ZEND_DECLARE_MODULE_GLOBALS(assert)
34
35
7.42k
#define ASSERTG(v) ZEND_MODULE_GLOBALS_ACCESSOR(assert, v)
36
37
#define SAFE_STRING(s) ((s)?(s):"")
38
39
enum {
40
  ASSERT_ACTIVE=1,
41
  ASSERT_CALLBACK,
42
  ASSERT_BAIL,
43
  ASSERT_WARNING,
44
  ASSERT_EXCEPTION
45
};
46
47
PHPAPI zend_class_entry *assertion_error_ce;
48
49
static PHP_INI_MH(OnChangeCallback) /* {{{ */
50
3.71k
{
51
3.71k
  if (EG(current_execute_data)) {
52
0
    if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
53
0
      zval_ptr_dtor(&ASSERTG(callback));
54
0
      ZVAL_UNDEF(&ASSERTG(callback));
55
0
    }
56
0
    if (new_value && (Z_TYPE(ASSERTG(callback)) != IS_UNDEF || ZSTR_LEN(new_value))) {
57
0
      ZVAL_STR_COPY(&ASSERTG(callback), new_value);
58
0
    }
59
3.71k
  } else {
60
3.71k
    if (ASSERTG(cb)) {
61
0
      pefree(ASSERTG(cb), 1);
62
0
    }
63
3.71k
    if (new_value && ZSTR_LEN(new_value)) {
64
0
      ASSERTG(cb) = pemalloc(ZSTR_LEN(new_value) + 1, 1);
65
0
      memcpy(ASSERTG(cb), ZSTR_VAL(new_value), ZSTR_LEN(new_value));
66
0
      ASSERTG(cb)[ZSTR_LEN(new_value)] = '\0';
67
3.71k
    } else {
68
3.71k
      ASSERTG(cb) = NULL;
69
3.71k
    }
70
3.71k
  }
71
3.71k
  return SUCCESS;
72
3.71k
}
73
/* }}} */
74
75
PHP_INI_BEGIN()
76
   STD_PHP_INI_BOOLEAN("assert.active",   "1",  PHP_INI_ALL,  OnUpdateBool,   active,       zend_assert_globals,    assert_globals)
77
   STD_PHP_INI_BOOLEAN("assert.bail",   "0",  PHP_INI_ALL,  OnUpdateBool,   bail,       zend_assert_globals,    assert_globals)
78
   STD_PHP_INI_BOOLEAN("assert.warning",  "1",  PHP_INI_ALL,  OnUpdateBool,   warning,      zend_assert_globals,    assert_globals)
79
   PHP_INI_ENTRY("assert.callback",   NULL, PHP_INI_ALL,  OnChangeCallback)
80
   STD_PHP_INI_BOOLEAN("assert.exception",  "1",  PHP_INI_ALL,  OnUpdateBool,   exception,      zend_assert_globals,    assert_globals)
81
PHP_INI_END()
82
83
static void php_assert_init_globals(zend_assert_globals *assert_globals_p) /* {{{ */
84
3.71k
{
85
3.71k
  ZVAL_UNDEF(&assert_globals_p->callback);
86
3.71k
  assert_globals_p->cb = NULL;
87
3.71k
}
88
/* }}} */
89
90
PHP_MINIT_FUNCTION(assert) /* {{{ */
91
3.71k
{
92
3.71k
  ZEND_INIT_MODULE_GLOBALS(assert, php_assert_init_globals, NULL);
93
94
3.71k
  REGISTER_INI_ENTRIES();
95
96
3.71k
  REGISTER_LONG_CONSTANT("ASSERT_ACTIVE", ASSERT_ACTIVE, CONST_CS|CONST_PERSISTENT);
97
3.71k
  REGISTER_LONG_CONSTANT("ASSERT_CALLBACK", ASSERT_CALLBACK, CONST_CS|CONST_PERSISTENT);
98
3.71k
  REGISTER_LONG_CONSTANT("ASSERT_BAIL", ASSERT_BAIL, CONST_CS|CONST_PERSISTENT);
99
3.71k
  REGISTER_LONG_CONSTANT("ASSERT_WARNING", ASSERT_WARNING, CONST_CS|CONST_PERSISTENT);
100
3.71k
  REGISTER_LONG_CONSTANT("ASSERT_EXCEPTION", ASSERT_EXCEPTION, CONST_CS|CONST_PERSISTENT);
101
102
3.71k
  return SUCCESS;
103
3.71k
}
104
/* }}} */
105
106
PHP_MSHUTDOWN_FUNCTION(assert) /* {{{ */
107
0
{
108
0
  if (ASSERTG(cb)) {
109
0
    pefree(ASSERTG(cb), 1);
110
0
    ASSERTG(cb) = NULL;
111
0
  }
112
0
  return SUCCESS;
113
0
}
114
/* }}} */
115
116
PHP_RSHUTDOWN_FUNCTION(assert) /* {{{ */
117
6.82M
{
118
6.82M
  if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
119
0
    zval_ptr_dtor(&ASSERTG(callback));
120
0
    ZVAL_UNDEF(&ASSERTG(callback));
121
0
  }
122
123
6.82M
  return SUCCESS;
124
6.82M
}
125
/* }}} */
126
127
PHP_MINFO_FUNCTION(assert) /* {{{ */
128
0
{
129
0
  DISPLAY_INI_ENTRIES();
130
0
}
131
/* }}} */
132
133
/* {{{ Checks if assertion is false */
134
PHP_FUNCTION(assert)
135
0
{
136
0
  zval *assertion;
137
0
  zend_string *description_str = NULL;
138
0
  zend_object *description_obj = NULL;
139
140
0
  if (!ASSERTG(active)) {
141
0
    RETURN_TRUE;
142
0
  }
143
144
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
145
0
    Z_PARAM_ZVAL(assertion)
146
0
    Z_PARAM_OPTIONAL
147
0
    Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(description_obj, zend_ce_throwable, description_str)
148
0
  ZEND_PARSE_PARAMETERS_END();
149
150
0
  if (zend_is_true(assertion)) {
151
0
    RETURN_TRUE;
152
0
  }
153
154
0
  if (description_obj) {
155
0
    GC_ADDREF(description_obj);
156
0
    zend_throw_exception_internal(description_obj);
157
0
    RETURN_THROWS();
158
0
  }
159
160
0
  if (Z_TYPE(ASSERTG(callback)) == IS_UNDEF && ASSERTG(cb)) {
161
0
    ZVAL_STRING(&ASSERTG(callback), ASSERTG(cb));
162
0
  }
163
164
0
  if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
165
0
    zval args[4];
166
0
    zval retval;
167
0
    uint32_t lineno = zend_get_executed_lineno();
168
0
    const char *filename = zend_get_executed_filename();
169
170
0
    ZVAL_STRING(&args[0], SAFE_STRING(filename));
171
0
    ZVAL_LONG(&args[1], lineno);
172
0
    ZVAL_NULL(&args[2]);
173
174
0
    ZVAL_FALSE(&retval);
175
176
0
    if (description_str) {
177
0
      ZVAL_STR(&args[3], description_str);
178
0
      call_user_function(NULL, NULL, &ASSERTG(callback), &retval, 4, args);
179
0
    } else {
180
0
      call_user_function(NULL, NULL, &ASSERTG(callback), &retval, 3, args);
181
0
    }
182
183
0
    zval_ptr_dtor(&args[0]);
184
0
    zval_ptr_dtor(&retval);
185
0
  }
186
187
0
  if (ASSERTG(exception)) {
188
0
    zend_throw_exception(assertion_error_ce, description_str ? ZSTR_VAL(description_str) : NULL, E_ERROR);
189
0
    if (ASSERTG(bail)) {
190
      /* When bail is turned on, the exception will not be caught. */
191
0
      zend_exception_error(EG(exception), E_ERROR);
192
0
    }
193
0
  } else if (ASSERTG(warning)) {
194
0
    php_error_docref(NULL, E_WARNING, "%s failed", description_str ? ZSTR_VAL(description_str) : "Assertion failed");
195
0
  }
196
197
0
  if (ASSERTG(bail)) {
198
0
    zend_throw_unwind_exit();
199
0
    RETURN_THROWS();
200
0
  } else {
201
0
    RETURN_FALSE;
202
0
  }
203
0
}
204
/* }}} */
205
206
/* {{{ Set/get the various assert flags */
207
PHP_FUNCTION(assert_options)
208
0
{
209
0
  zval *value = NULL;
210
0
  zend_long what;
211
0
  bool oldint;
212
0
  int ac = ZEND_NUM_ARGS();
213
0
  zend_string *key;
214
215
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
216
0
    Z_PARAM_LONG(what)
217
0
    Z_PARAM_OPTIONAL
218
0
    Z_PARAM_ZVAL(value)
219
0
  ZEND_PARSE_PARAMETERS_END();
220
221
0
  switch (what) {
222
0
  case ASSERT_ACTIVE:
223
0
    oldint = ASSERTG(active);
224
0
    if (ac == 2) {
225
0
      zend_string *value_str = zval_try_get_string(value);
226
0
      if (UNEXPECTED(!value_str)) {
227
0
        RETURN_THROWS();
228
0
      }
229
230
0
      key = zend_string_init("assert.active", sizeof("assert.active")-1, 0);
231
0
      zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
232
0
      zend_string_release_ex(key, 0);
233
0
      zend_string_release_ex(value_str, 0);
234
0
    }
235
0
    RETURN_LONG(oldint);
236
0
    break;
237
238
0
  case ASSERT_BAIL:
239
0
    oldint = ASSERTG(bail);
240
0
    if (ac == 2) {
241
0
      zend_string *value_str = zval_try_get_string(value);
242
0
      if (UNEXPECTED(!value_str)) {
243
0
        RETURN_THROWS();
244
0
      }
245
246
0
      key = zend_string_init("assert.bail", sizeof("assert.bail")-1, 0);
247
0
      zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
248
0
      zend_string_release_ex(key, 0);
249
0
      zend_string_release_ex(value_str, 0);
250
0
    }
251
0
    RETURN_LONG(oldint);
252
0
    break;
253
254
0
  case ASSERT_WARNING:
255
0
    oldint = ASSERTG(warning);
256
0
    if (ac == 2) {
257
0
      zend_string *value_str = zval_try_get_string(value);
258
0
      if (UNEXPECTED(!value_str)) {
259
0
        RETURN_THROWS();
260
0
      }
261
262
0
      key = zend_string_init("assert.warning", sizeof("assert.warning")-1, 0);
263
0
      zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
264
0
      zend_string_release_ex(key, 0);
265
0
      zend_string_release_ex(value_str, 0);
266
0
    }
267
0
    RETURN_LONG(oldint);
268
0
    break;
269
270
0
  case ASSERT_CALLBACK:
271
0
    if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
272
0
      ZVAL_COPY(return_value, &ASSERTG(callback));
273
0
    } else if (ASSERTG(cb)) {
274
0
      RETVAL_STRING(ASSERTG(cb));
275
0
    } else {
276
0
      RETVAL_NULL();
277
0
    }
278
279
0
    if (ac == 2) {
280
0
      zval_ptr_dtor(&ASSERTG(callback));
281
0
      if (Z_TYPE_P(value) == IS_NULL) {
282
0
        ZVAL_UNDEF(&ASSERTG(callback));
283
0
      } else {
284
0
        ZVAL_COPY(&ASSERTG(callback), value);
285
0
      }
286
0
    }
287
0
    return;
288
289
0
  case ASSERT_EXCEPTION:
290
0
    oldint = ASSERTG(exception);
291
0
    if (ac == 2) {
292
0
      zend_string *val = zval_try_get_string(value);
293
0
      if (UNEXPECTED(!val)) {
294
0
        RETURN_THROWS();
295
0
      }
296
297
0
      key = zend_string_init("assert.exception", sizeof("assert.exception")-1, 0);
298
0
      zend_alter_ini_entry_ex(key, val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
299
0
      zend_string_release_ex(val, 0);
300
0
      zend_string_release_ex(key, 0);
301
0
    }
302
0
    RETURN_LONG(oldint);
303
0
    break;
304
305
0
  default:
306
0
    zend_argument_value_error(1, "must be an ASSERT_* constant");
307
0
    RETURN_THROWS();
308
0
  }
309
0
}
310
/* }}} */