Coverage Report

Created: 2022-10-14 11:19

/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
7.29k
#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.64k
{
51
3.64k
  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.64k
  } else {
60
3.64k
    if (ASSERTG(cb)) {
61
0
      pefree(ASSERTG(cb), 1);
62
0
    }
63
3.64k
    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.64k
    } else {
68
3.64k
      ASSERTG(cb) = NULL;
69
3.64k
    }
70
3.64k
  }
71
3.64k
  return SUCCESS;
72
3.64k
}
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",  "0",  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.64k
{
85
3.64k
  ZVAL_UNDEF(&assert_globals_p->callback);
86
3.64k
  assert_globals_p->cb = NULL;
87
3.64k
}
88
/* }}} */
89
90
PHP_MINIT_FUNCTION(assert) /* {{{ */
91
3.64k
{
92
3.64k
  zend_class_entry ce;
93
94
3.64k
  ZEND_INIT_MODULE_GLOBALS(assert, php_assert_init_globals, NULL);
95
96
3.64k
  REGISTER_INI_ENTRIES();
97
98
3.64k
  REGISTER_LONG_CONSTANT("ASSERT_ACTIVE", ASSERT_ACTIVE, CONST_CS|CONST_PERSISTENT);
99
3.64k
  REGISTER_LONG_CONSTANT("ASSERT_CALLBACK", ASSERT_CALLBACK, CONST_CS|CONST_PERSISTENT);
100
3.64k
  REGISTER_LONG_CONSTANT("ASSERT_BAIL", ASSERT_BAIL, CONST_CS|CONST_PERSISTENT);
101
3.64k
  REGISTER_LONG_CONSTANT("ASSERT_WARNING", ASSERT_WARNING, CONST_CS|CONST_PERSISTENT);
102
3.64k
  REGISTER_LONG_CONSTANT("ASSERT_EXCEPTION", ASSERT_EXCEPTION, CONST_CS|CONST_PERSISTENT);
103
104
3.64k
  INIT_CLASS_ENTRY(ce, "AssertionError", NULL);
105
3.64k
  assertion_error_ce = zend_register_internal_class_ex(&ce, zend_ce_error);
106
107
3.64k
  return SUCCESS;
108
3.64k
}
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
395k
{
123
395k
  if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
124
0
    zval_ptr_dtor(&ASSERTG(callback));
125
0
    ZVAL_UNDEF(&ASSERTG(callback));
126
0
  }
127
128
395k
  return SUCCESS;
129
395k
}
130
/* }}} */
131
132
PHP_MINFO_FUNCTION(assert) /* {{{ */
133
0
{
134
0
  DISPLAY_INI_ENTRIES();
135
0
}
136
/* }}} */
137
138
/* {{{ proto int assert(string|bool assertion[, mixed description])
139
   Checks if assertion is false */
140
PHP_FUNCTION(assert)
141
0
{
142
0
  zval *assertion;
143
0
  zval *description = NULL;
144
145
0
  if (! ASSERTG(active)) {
146
0
    RETURN_TRUE;
147
0
  }
148
149
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
150
0
    Z_PARAM_ZVAL(assertion)
151
0
    Z_PARAM_OPTIONAL
152
0
    Z_PARAM_ZVAL(description)
153
0
  ZEND_PARSE_PARAMETERS_END();
154
155
0
  if (zend_is_true(assertion)) {
156
0
    RETURN_TRUE;
157
0
  }
158
159
0
  if (Z_TYPE(ASSERTG(callback)) == IS_UNDEF && ASSERTG(cb)) {
160
0
    ZVAL_STRING(&ASSERTG(callback), ASSERTG(cb));
161
0
  }
162
163
0
  if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
164
0
    zval args[4];
165
0
    zval retval;
166
0
    uint32_t lineno = zend_get_executed_lineno();
167
0
    const char *filename = zend_get_executed_filename();
168
169
0
    ZVAL_STRING(&args[0], SAFE_STRING(filename));
170
0
    ZVAL_LONG(&args[1], lineno);
171
0
    ZVAL_NULL(&args[2]);
172
173
0
    ZVAL_FALSE(&retval);
174
175
    /* XXX do we want to check for error here? */
176
0
    if (!description) {
177
0
      call_user_function(NULL, NULL, &ASSERTG(callback), &retval, 3, args);
178
0
      zval_ptr_dtor(&(args[2]));
179
0
      zval_ptr_dtor(&(args[0]));
180
0
    } else {
181
0
      ZVAL_STR(&args[3], zval_get_string(description));
182
0
      call_user_function(NULL, NULL, &ASSERTG(callback), &retval, 4, args);
183
0
      zval_ptr_dtor(&(args[3]));
184
0
      zval_ptr_dtor(&(args[2]));
185
0
      zval_ptr_dtor(&(args[0]));
186
0
    }
187
188
0
    zval_ptr_dtor(&retval);
189
0
  }
190
191
0
  if (ASSERTG(exception)) {
192
0
    if (!description) {
193
0
      zend_throw_exception(assertion_error_ce, NULL, E_ERROR);
194
0
    } else if (Z_TYPE_P(description) == IS_OBJECT &&
195
0
      instanceof_function(Z_OBJCE_P(description), zend_ce_throwable)) {
196
0
      Z_ADDREF_P(description);
197
0
      zend_throw_exception_object(description);
198
0
    } else {
199
0
      zend_string *str = zval_get_string(description);
200
0
      zend_throw_exception(assertion_error_ce, ZSTR_VAL(str), E_ERROR);
201
0
      zend_string_release_ex(str, 0);
202
0
    }
203
0
  } else if (ASSERTG(warning)) {
204
0
    if (!description) {
205
0
      php_error_docref(NULL, E_WARNING, "Assertion failed");
206
0
    } else {
207
0
      zend_string *str = zval_get_string(description);
208
0
      php_error_docref(NULL, E_WARNING, "%s failed", ZSTR_VAL(str));
209
0
      zend_string_release_ex(str, 0);
210
0
    }
211
0
  }
212
213
0
  if (ASSERTG(bail)) {
214
0
    zend_bailout();
215
0
  }
216
217
0
  RETURN_FALSE;
218
0
}
219
/* }}} */
220
221
/* {{{ proto mixed assert_options(int what [, mixed value])
222
   Set/get the various assert flags */
223
PHP_FUNCTION(assert_options)
224
0
{
225
0
  zval *value = NULL;
226
0
  zend_long what;
227
0
  zend_bool oldint;
228
0
  int ac = ZEND_NUM_ARGS();
229
0
  zend_string *key;
230
231
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
232
0
    Z_PARAM_LONG(what)
233
0
    Z_PARAM_OPTIONAL
234
0
    Z_PARAM_ZVAL(value)
235
0
  ZEND_PARSE_PARAMETERS_END();
236
237
0
  switch (what) {
238
0
  case ASSERT_ACTIVE:
239
0
    oldint = ASSERTG(active);
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;
244
0
      }
245
246
0
      key = zend_string_init("assert.active", sizeof("assert.active")-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_BAIL:
255
0
    oldint = ASSERTG(bail);
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;
260
0
      }
261
262
0
      key = zend_string_init("assert.bail", sizeof("assert.bail")-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_WARNING:
271
0
    oldint = ASSERTG(warning);
272
0
    if (ac == 2) {
273
0
      zend_string *value_str = zval_try_get_string(value);
274
0
      if (UNEXPECTED(!value_str)) {
275
0
        return;
276
0
      }
277
278
0
      key = zend_string_init("assert.warning", sizeof("assert.warning")-1, 0);
279
0
      zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
280
0
      zend_string_release_ex(key, 0);
281
0
      zend_string_release_ex(value_str, 0);
282
0
    }
283
0
    RETURN_LONG(oldint);
284
0
    break;
285
286
0
  case ASSERT_CALLBACK:
287
0
    if (Z_TYPE(ASSERTG(callback)) != IS_UNDEF) {
288
0
      ZVAL_COPY(return_value, &ASSERTG(callback));
289
0
    } else if (ASSERTG(cb)) {
290
0
      RETVAL_STRING(ASSERTG(cb));
291
0
    } else {
292
0
      RETVAL_NULL();
293
0
    }
294
0
    if (ac == 2) {
295
0
      zval_ptr_dtor(&ASSERTG(callback));
296
0
      ZVAL_COPY(&ASSERTG(callback), value);
297
0
    }
298
0
    return;
299
300
0
  case ASSERT_EXCEPTION:
301
0
    oldint = ASSERTG(exception);
302
0
    if (ac == 2) {
303
0
      zend_string *val = zval_try_get_string(value);
304
0
      if (UNEXPECTED(!val)) {
305
0
        return;
306
0
      }
307
308
0
      key = zend_string_init("assert.exception", sizeof("assert.exception")-1, 0);
309
0
      zend_alter_ini_entry_ex(key, val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
310
0
      zend_string_release_ex(val, 0);
311
0
      zend_string_release_ex(key, 0);
312
0
    }
313
0
    RETURN_LONG(oldint);
314
0
    break;
315
316
0
  default:
317
0
    zend_argument_value_error(1, "must have a valid value");
318
0
    break;
319
0
  }
320
321
0
  return;
322
0
}
323
/* }}} */