Skip to content

maintainer-strict-api - A tool to check and enforce encapsulation #1508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Zend/Zend.m4
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,22 @@ fi
AC_MSG_CHECKING(whether to enable zend signal handling)
AC_MSG_RESULT($ZEND_SIGNALS)

AC_ARG_ENABLE(maintainer-strict-api,
[ --enable-maintainer-strict-api Check strict API compliance - for code maintainers only!!],[
ZEND_CORE_STRICT_API=$enableval
],[
ZEND_CORE_STRICT_API=no
])

if test "$ZEND_CORE_STRICT_API" = "yes"; then
AC_DEFINE(ZEND_CORE_STRICT_API, 1, [Check strict API compliance])
else
AC_DEFINE(ZEND_CORE_STRICT_API, 0, [Check strict API compliance])
fi

AC_MSG_CHECKING(whether to check strict API compliance)
AC_MSG_RESULT($ZEND_CORE_STRICT_API)

])

AC_DEFUN([LIBZEND_CPLUSPLUS_CHECKS],[
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr) {
ast->kind = ZEND_AST_ZVAL;
ast->attr = attr;
ZVAL_COPY_VALUE(&ast->val, zv);
ast->val.u2.lineno = CG(zend_lineno);
Z_LINENO(ast->val) = CG(zend_lineno);
return (zend_ast *) ast;
}

Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ typedef struct _zend_ast_list {
zend_ast *child[1];
} zend_ast_list;

/* Lineno is stored in val.u2.lineno */
/* Lineno is available using Z_LINENO(val) */
typedef struct _zend_ast_zval {
zend_ast_kind kind;
zend_ast_attr attr;
Expand Down Expand Up @@ -237,7 +237,7 @@ static zend_always_inline uint32_t zend_ast_get_num_children(zend_ast *ast) {
static zend_always_inline uint32_t zend_ast_get_lineno(zend_ast *ast) {
if (ast->kind == ZEND_AST_ZVAL) {
zval *zv = zend_ast_get_zval(ast);
return zv->u2.lineno;
return Z_LINENO_P(zv);
} else {
return ast->lineno;
}
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1969,7 +1969,7 @@ static int copy_function_name(zval *zv, int num_args, va_list args, zend_hash_ke
char *disable_functions = INI_STR("disable_functions");

if ((*exclude_disabled == 1) && (disable_functions != NULL)) {
if (strstr(disable_functions, func->common.function_name->val) == NULL) {
if (strstr(disable_functions, ZSTR_VAL(func->common.function_name)) == NULL) {
add_next_index_str(internal_ar, zend_string_copy(hash_key->key));
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ struct _zend_execute_data {
} while (0)

#define ZEND_CALL_NUM_ARGS(call) \
(call)->This.u2.num_args
Z_NUM_ARGS((call)->This)

#define ZEND_CALL_FRAME_SLOT \
((int)((ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))))
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_generators.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
fast_call = ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[finally_op_end].op1.var);
Z_OBJ_P(fast_call) = EG(exception);
EG(exception) = NULL;
fast_call->u2.lineno = (uint32_t)-1;
Z_LINENO_P(fast_call) = (uint32_t)-1;

ex->opline = &ex->func->op_array.opcodes[finally_op_num];
generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
Expand Down
12 changes: 6 additions & 6 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -524,17 +524,17 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
(EXPECTED(ZSTR_H(str) == ZSTR_H(member)) &&
EXPECTED(ZSTR_LEN(str) == ZSTR_LEN(member)) &&
EXPECTED(memcmp(ZSTR_VAL(str), ZSTR_VAL(member), ZSTR_LEN(member)) == 0))) {
return &zv->u2.property_guard;
} else if (EXPECTED(zv->u2.property_guard == 0)) {
return &zv->_ZSTRICT_FIELD(zval_struct,u2).property_guard;
} else if (EXPECTED(zv->_ZSTRICT_FIELD(zval_struct,u2).property_guard == 0)) {
zend_string_release(Z_STR_P(zv));
ZVAL_STR_COPY(zv, member);
return &zv->u2.property_guard;
return &zv->_ZSTRICT_FIELD(zval_struct,u2).property_guard;
} else {
ALLOC_HASHTABLE(guards);
zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0);
/* mark pointer as "special" using low bit */
zend_hash_add_new_ptr(guards, member,
(void*)(((zend_uintptr_t)&zv->u2.property_guard) | 1));
(void*)(((zend_uintptr_t)&zv->_ZSTRICT_FIELD(zval_struct,u2).property_guard) | 1));
zend_string_release(Z_STR_P(zv));
ZVAL_ARR(zv, guards);
}
Expand All @@ -549,8 +549,8 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF);
GC_FLAGS(zobj) |= IS_OBJ_HAS_GUARDS;
ZVAL_STR_COPY(zv, member);
zv->u2.property_guard = 0;
return &zv->u2.property_guard;
zv->_ZSTRICT_FIELD(zval_struct,u2).property_guard = 0;
return &zv->_ZSTRICT_FIELD(zval_struct,u2).property_guard;
}
/* we have to allocate uint32_t separately because ht->arData may be reallocated */
ptr = (uint32_t*)emalloc(sizeof(uint32_t));
Expand Down
6 changes: 3 additions & 3 deletions Zend/zend_operators.c
Original file line number Diff line number Diff line change
Expand Up @@ -2793,8 +2793,8 @@ ZEND_API zend_long ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string
zend_long lval1 = 0, lval2 = 0;
double dval1 = 0.0, dval2 = 0.0;

if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, 0, &oflow1)) &&
(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, 0, &oflow2))) {
if ((ret1 = is_numeric_string_ex(ZSTR_VAL(s1), ZSTR_LEN(s1), &lval1, &dval1, 0, &oflow1)) &&
(ret2 = is_numeric_string_ex(ZSTR_VAL(s2), ZSTR_LEN(s2), &lval2, &dval2, 0, &oflow2))) {
#if ZEND_ULONG_MAX == 0xFFFFFFFF
if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
Expand Down Expand Up @@ -2831,7 +2831,7 @@ ZEND_API zend_long ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string
} else {
int strcmp_ret;
string_cmp:
strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
strcmp_ret = zend_binary_strcmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2));
return ZEND_NORMALIZE_BOOL(strcmp_ret);
}
}
Expand Down
36 changes: 16 additions & 20 deletions Zend/zend_operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,10 +435,6 @@ ZEND_API void zend_update_current_locale(void);
#define zend_update_current_locale()
#endif

/* The offset in bytes between the value and type fields of a zval */
#define ZVAL_OFFSETOF_TYPE \
(offsetof(zval, u1.type_info) - offsetof(zval, value))

static zend_always_inline void fast_long_increment_function(zval *op1)
{
#if PHP_HAVE_BUILTIN_SADDL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
Expand Down Expand Up @@ -466,7 +462,7 @@ static zend_always_inline void fast_long_increment_function(zval *op1)
"movl %1, %c2(%0)\n"
"0:"
:
: "r"(&op1->value),
: "r"(&_Z_VALUE_P(op1)),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
: "cc", "memory");
Expand All @@ -479,7 +475,7 @@ static zend_always_inline void fast_long_increment_function(zval *op1)
"movl %1, %c2(%0)\n"
"0:"
:
: "r"(&op1->value),
: "r"(&_Z_VALUE_P(op1)),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
: "cc", "memory");
Expand Down Expand Up @@ -520,7 +516,7 @@ static zend_always_inline void fast_long_decrement_function(zval *op1)
"movl %1,%c2(%0)\n"
"0:"
:
: "r"(&op1->value),
: "r"(&_Z_VALUE_P(op1)),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
: "cc", "memory");
Expand All @@ -533,7 +529,7 @@ static zend_always_inline void fast_long_decrement_function(zval *op1)
"movl %1,%c2(%0)\n"
"0:"
:
: "r"(&op1->value),
: "r"(&_Z_VALUE_P(op1)),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
: "cc", "memory");
Expand Down Expand Up @@ -582,9 +578,9 @@ static zend_always_inline void fast_long_add_function(zval *result, zval *op1, z
"fstpl (%0)\n"
"1:"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
: "r"(&_Z_VALUE_P(result)),
"r"(&_Z_VALUE_P(op1)),
"r"(&_Z_VALUE_P(op2)),
"n"(IS_LONG),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
Expand All @@ -605,9 +601,9 @@ static zend_always_inline void fast_long_add_function(zval *result, zval *op1, z
"fstpl (%0)\n"
"1:"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
: "r"(&_Z_VALUE_P(result)),
"r"(&_Z_VALUE_P(op1)),
"r"(&_Z_VALUE_P(op2)),
"n"(IS_LONG),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
Expand Down Expand Up @@ -689,9 +685,9 @@ static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, z
"fstpl (%0)\n"
"1:"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
: "r"(&_Z_VALUE_P(result)),
"r"(&_Z_VALUE_P(op1)),
"r"(&_Z_VALUE_P(op2)),
"n"(IS_LONG),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
Expand All @@ -716,9 +712,9 @@ static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, z
"fstpl (%0)\n"
"1:"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
: "r"(&_Z_VALUE_P(result)),
"r"(&_Z_VALUE_P(op1)),
"r"(&_Z_VALUE_P(op2)),
"n"(IS_LONG),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
Expand Down
66 changes: 66 additions & 0 deletions Zend/zend_strict.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) 1998-2017 Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Francois Laupretre <francois@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
/*============================================================================
This file implements the '--enable-maintainer-strict-api' configure option.

When this option is set, the names of the protected structure fields (those
defined using using the _ZSTRICT_FIELD() macro) are modified, causing
a compile failure when code attempts a direct access to the structure
fields. This allows to detect violations of the published API.

-------------------------------- WARNING ------------------------------------
Including this file is reserved to source files located in the Zend
subdirectory. Outside the Zend directory, this file can be included indirectly,
through another zend_xxx include, but not directly. The macros defined below
should never be used in any piece of code outside the Zend subdirectory.
============================================================================*/

#ifndef ZEND_STRICT_H
#define ZEND_STRICT_H

#include "php_config.h"

#ifdef ZEND_EXT_STRICT_API
# define __ZEND_STRICT_API ZEND_EXT_STRICT_API
#else
# ifdef ZEND_CORE_STRICT_API
# define __ZEND_STRICT_API ZEND_CORE_STRICT_API
# else
# define __ZEND_STRICT_API 0
# endif
#endif
#if __ZEND_STRICT_API
# define _ZSTRICT_NAME(_type,_prefix,_elt) _zstrict_ ## _type ## _ ## _prefix ## _ ## _elt
# define _ZSTRICT_FIELD(_prefix,_elt) _ZSTRICT_NAME(field,_prefix,_elt)
# define ZEND_STRICT_API
#else
# define _ZSTRICT_FIELD(_prefix,_elt) _elt
#endif
#undef __ZEND_STRICT_API

/*-------------------------------------------------------------------------*/
#endif /* ZEND_STRICT_H */

/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* indent-tabs-mode: t
* End:
*/
9 changes: 5 additions & 4 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define ZEND_STRING_H

#include "zend.h"
#include "zend_strict.h"

BEGIN_EXTERN_C()

Expand All @@ -38,9 +39,9 @@ END_EXTERN_C()

/* Shortcuts */

#define ZSTR_VAL(zstr) (zstr)->val
#define ZSTR_LEN(zstr) (zstr)->len
#define ZSTR_H(zstr) (zstr)->h
#define ZSTR_VAL(zstr) (zstr)->_ZSTRICT_FIELD(zend_string,val)
#define ZSTR_LEN(zstr) (zstr)->_ZSTRICT_FIELD(zend_string,len)
#define ZSTR_H(zstr) (zstr)->_ZSTRICT_FIELD(zend_string,h)
#define ZSTR_HASH(zstr) zend_string_hash_val(zstr)

/* Compatibility macros */
Expand All @@ -58,7 +59,7 @@ END_EXTERN_C()

#define ZSTR_EMPTY_ALLOC() CG(empty_string)

#define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val)
#define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, _ZSTRICT_FIELD(zend_string,val))

#define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)

Expand Down
Loading