Coverage Report

Created: 2022-02-19 20:31

/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
   | http://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
  zend_bool active;
28
  zend_bool bail;
29
  zend_bool warning;
30
  zend_bool exception;
31
ZEND_END_MODULE_GLOBALS(assert)
32
33
ZEND_DECLARE_MODULE_GLOBALS(assert)
34
35
static zend_class_entry *assertion_error_ce;
36
37
19.9k
#define ASSERTG(v) ZEND_MODULE_GLOBALS_ACCESSOR(assert, v)
38
39
#define SAFE_STRING(s) ((s)?(s):"")
40
41
enum {
42
  ASSERT_ACTIVE=1,
43
  ASSERT_CALLBACK,
44
  ASSERT_BAIL,
45
  ASSERT_WARNING,
46
  ASSERT_EXCEPTION
47
};
48
49
static PHP_INI_MH(OnChangeCallback) /* {{{ */
50
3.50k
{
51
3.50k
  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.50k
  } else {
60
3.50k
    if (ASSERTG(cb)) {
61
0
      pefree(ASSERTG(cb), 1);
62
0
    }
63
3.50k
    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.50k
    } else {
68
3.50k
      ASSERTG(cb) = NULL;
69
3.50k
    }
70
3.50k
  }
71
3.50k
  return SUCCESS;
72
3.50k
}
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.50k
{
85
3.50k
  ZVAL_UNDEF(&assert_globals_p->callback);
86
3.50k
  assert_globals_p->cb = NULL;
87
3.50k
}
88
/* }}} */
89
90
PHP_MINIT_FUNCTION(assert) /* {{{ */
91
3.50k
{
92
3.50k
  zend_class_entry ce;
93
94
3.50k
  ZEND_INIT_MODULE_GLOBALS(assert, php_assert_init_globals, NULL);
95
96
3.50k
  REGISTER_INI_ENTRIES();
97
98
3.50k
  REGISTER_LONG_CONSTANT("ASSERT_ACTIVE", ASSERT_ACTIVE, CONST_CS|CONST_PERSISTENT);
99
3.50k
  REGISTER_LONG_CONSTANT("ASSERT_CALLBACK", ASSERT_CALLBACK, CONST_CS|CONST_PERSISTENT);
100
3.50k
  REGISTER_LONG_CONSTANT("ASSERT_BAIL", ASSERT_BAIL, CONST_CS|CONST_PERSISTENT);
101
3.50k
  REGISTER_LONG_CONSTANT("ASSERT_WARNING", ASSERT_WARNING, CONST_CS|CONST_PERSISTENT);
102
3.50k
  REGISTER_LONG_CONSTANT("ASSERT_EXCEPTION", ASSERT_EXCEPTION, CONST_CS|CONST_PERSISTENT);
103
104
3.50k
  INIT_CLASS_ENTRY(ce, "AssertionError", NULL);
105
3.50k
  assertion_error_ce = zend_register_internal_class_ex(&ce, zend_ce_error);
106
107
3.50k
  return SUCCESS;
108
3.50k
}
109
/* }}} */
110
111
PHP_MSHUTDOWN_FUNCTION(assert) /* {{{ */
112
0
{
113
0
  if (ASSERTG(cb)) {
114
0
    pefree(ASSERTG(cb), 1);
115
0
    ASSERTG(cb) = NULL;
116
0
  }
117
0
  return SUCCESS;
118
0
}
119
/* }}} */
120
121
PHP_RSHUTDOWN_FUNCTION(assert) /* {{{ */
122
324k
{
123
324k
  if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
124
0
    zval_ptr_dtor(&ASSERTG(callback));
125
0
    ZVAL_UNDEF(&ASSERTG(callback));
126
0
  }
127
128
324k
  return SUCCESS;
129
324k
}
130
/* }}} */
131
132
PHP_MINFO_FUNCTION(assert) /* {{{ */
133
543
{
134
543
  DISPLAY_INI_ENTRIES();
135
543
}
136
/* }}} */
137
138
/* {{{ Checks if assertion is false */
139
PHP_FUNCTION(assert)
140
9.88k
{
141
9.88k
  zval *assertion;
142
9.88k
  zend_string *description_str = NULL;
143
9.88k
  zend_object *description_obj = NULL;
144
145
9.88k
  if (!ASSERTG(active)) {
146
0
    RETURN_TRUE;
147
0
  }
148
149
29.6k
  ZEND_PARSE_PARAMETERS_START(1, 2)
150
9.88k
    Z_PARAM_ZVAL(assertion)
151
9.88k
    Z_PARAM_OPTIONAL
152
19.7k
    Z_PARAM_STR_OR_OBJ_OF_CLASS_OR_NULL(description_str, description_obj, zend_ce_throwable)
153
9.88k
  ZEND_PARSE_PARAMETERS_END();
154
155
9.88k
  if (zend_is_true(assertion)) {
156
8.85k
    RETURN_TRUE;
157
8.85k
  }
158
159
1.03k
  if (description_obj) {
160
33
    GC_ADDREF(description_obj);
161
33
    zend_throw_exception_internal(description_obj);
162
33
    RETURN_THROWS();
163
33
  }
164
165
1.00k
  if (Z_TYPE(ASSERTG(callback)) == IS_UNDEF && ASSERTG(cb)) {
166
0
    ZVAL_STRING(&ASSERTG(callback), ASSERTG(cb));
167
0
  }
168
169
1.00k
  if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
170
0
    zval args[4];
171
0
    zval retval;
172
0
    uint32_t lineno = zend_get_executed_lineno();
173
0
    const char *filename = zend_get_executed_filename();
174
175
0
    ZVAL_STRING(&args[0], SAFE_STRING(filename));
176
0
    ZVAL_LONG(&args[1], lineno);
177
0
    ZVAL_NULL(&args[2]);
178
179
0
    ZVAL_FALSE(&retval);
180
181
0
    if (description_str) {
182
0
      ZVAL_STR(&args[3], description_str);
183
0
      call_user_function(NULL, NULL, &ASSERTG(callback), &retval, 4, args);
184
0
      zval_ptr_dtor(&(args[3]));
185
0
      zval_ptr_dtor(&(args[2]));
186
0
      zval_ptr_dtor(&(args[0]));
187
0
    } else {
188
0
      call_user_function(NULL, NULL, &ASSERTG(callback), &retval, 3, args);
189
0
      zval_ptr_dtor(&(args[2]));
190
0
      zval_ptr_dtor(&(args[0]));
191
0
    }
192
193
0
    zval_ptr_dtor(&retval);
194
0
  }
195
196
1.00k
  if (ASSERTG(exception)) {
197
1.00k
    zend_throw_exception(assertion_error_ce, description_str ? ZSTR_VAL(description_str) : NULL, E_ERROR);
198
0
  } else if (ASSERTG(warning)) {
199
0
    php_error_docref(NULL, E_WARNING, "%s failed", description_str ? ZSTR_VAL(description_str) : "Assertion failed");
200
0
  }
201
202
1.00k
  if (ASSERTG(bail)) {
203
0
    zend_bailout();
204
0
  }
205
206
1.00k
  RETURN_FALSE;
207
1.00k
}
208
/* }}} */
209
210
/* {{{ Set/get the various assert flags */
211
PHP_FUNCTION(assert_options)
212
39
{
213
39
  zval *value = NULL;
214
39
  zend_long what;
215
39
  zend_bool oldint;
216
39
  int ac = ZEND_NUM_ARGS();
217
39
  zend_string *key;
218
219
117
  ZEND_PARSE_PARAMETERS_START(1, 2)
220
39
    Z_PARAM_LONG(what)
221
39
    Z_PARAM_OPTIONAL
222
0
    Z_PARAM_ZVAL(value)
223
39
  ZEND_PARSE_PARAMETERS_END();
224
225
39
  switch (what) {
226
0
  case ASSERT_ACTIVE:
227
0
    oldint = ASSERTG(active);
228
0
    if (ac == 2) {
229
0
      zend_string *value_str = zval_try_get_string(value);
230
0
      if (UNEXPECTED(!value_str)) {
231
0
        RETURN_THROWS();
232
0
      }
233
234
0
      key = zend_string_init("assert.active", sizeof("assert.active")-1, 0);
235
0
      zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
236
0
      zend_string_release_ex(key, 0);
237
0
      zend_string_release_ex(value_str, 0);
238
0
    }
239
0
    RETURN_LONG(oldint);
240
0
    break;
241
242
0
  case ASSERT_BAIL:
243
0
    oldint = ASSERTG(bail);
244
0
    if (ac == 2) {
245
0
      zend_string *value_str = zval_try_get_string(value);
246
0
      if (UNEXPECTED(!value_str)) {
247
0
        RETURN_THROWS();
248
0
      }
249
250
0
      key = zend_string_init("assert.bail", sizeof("assert.bail")-1, 0);
251
0
      zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
252
0
      zend_string_release_ex(key, 0);
253
0
      zend_string_release_ex(value_str, 0);
254
0
    }
255
0
    RETURN_LONG(oldint);
256
0
    break;
257
258
39
  case ASSERT_WARNING:
259
39
    oldint = ASSERTG(warning);
260
39
    if (ac == 2) {
261
0
      zend_string *value_str = zval_try_get_string(value);
262
0
      if (UNEXPECTED(!value_str)) {
263
0
        RETURN_THROWS();
264
0
      }
265
266
0
      key = zend_string_init("assert.warning", sizeof("assert.warning")-1, 0);
267
0
      zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
268
0
      zend_string_release_ex(key, 0);
269
0
      zend_string_release_ex(value_str, 0);
270
0
    }
271
39
    RETURN_LONG(oldint);
272
0
    break;
273
274
0
  case ASSERT_CALLBACK:
275
0
    if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
276
0
      ZVAL_COPY(return_value, &ASSERTG(callback));
277
0
    } else if (ASSERTG(cb)) {
278
0
      RETVAL_STRING(ASSERTG(cb));
279
0
    } else {
280
0
      RETVAL_NULL();
281
0
    }
282
283
0
    if (ac == 2) {
284
0
      zval_ptr_dtor(&ASSERTG(callback));
285
0
      if (Z_TYPE_P(value) == IS_NULL) {
286
0
        ZVAL_UNDEF(&ASSERTG(callback));
287
0
      } else {
288
0
        ZVAL_COPY(&ASSERTG(callback), value);
289
0
      }
290
0
    }
291
0
    return;
292
293
0
  case ASSERT_EXCEPTION:
294
0
    oldint = ASSERTG(exception);
295
0
    if (ac == 2) {
296
0
      zend_string *val = zval_try_get_string(value);
297
0
      if (UNEXPECTED(!val)) {
298
0
        RETURN_THROWS();
299
0
      }
300
301
0
      key = zend_string_init("assert.exception", sizeof("assert.exception")-1, 0);
302
0
      zend_alter_ini_entry_ex(key, val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
303
0
      zend_string_release_ex(val, 0);
304
0
      zend_string_release_ex(key, 0);
305
0
    }
306
0
    RETURN_LONG(oldint);
307
0
    break;
308
309
0
  default:
310
0
    zend_argument_value_error(1, "must be an ASSERT_* constant");
311
0
    RETURN_THROWS();
312
39
  }
313
39
}
314
/* }}} */