Allocate zend_strings with correct size

For me (32bit) sizeof(zend_string) is 20, which means that the
char[1] array at the end is padded with three bytes. Thus allocating
based on sizeof(zend_string)-1 overallocates by those 3 padding bytes.

This commit fixes the allocation size, by using XtOffsetOf.
This commit is contained in:
Nikita Popov 2014-04-23 19:05:16 +02:00
parent 20580a511c
commit 08ae88157b
8 changed files with 44 additions and 42 deletions

View File

@ -347,6 +347,36 @@ void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((nore
# define UNEXPECTED(condition) (condition) # define UNEXPECTED(condition) (condition)
#endif #endif
#ifndef XtOffsetOf
# if defined(CRAY) || (defined(__ARMCC_VERSION) && !defined(LINUX))
# ifdef __STDC__
# define XtOffset(p_type, field) _Offsetof(p_type, field)
# else
# ifdef CRAY2
# define XtOffset(p_type, field) \
(sizeof(int)*((unsigned int)&(((p_type)NULL)->field)))
# else /* !CRAY2 */
# define XtOffset(p_type, field) ((unsigned int)&(((p_type)NULL)->field))
# endif /* !CRAY2 */
# endif /* __STDC__ */
# else /* ! (CRAY || __arm) */
# define XtOffset(p_type, field) \
((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL)))
# endif /* !CRAY */
# ifdef offsetof
# define XtOffsetOf(s_type, field) offsetof(s_type, field)
# else
# define XtOffsetOf(s_type, field) XtOffset(s_type*, field)
# endif
#endif
#include "zend_string.h" #include "zend_string.h"
static zend_always_inline zend_uint zval_refcount_p(zval* pz) { static zend_always_inline zend_uint zval_refcount_p(zval* pz) {

View File

@ -27,36 +27,6 @@
#define ZEND_INI_ALL (ZEND_INI_USER|ZEND_INI_PERDIR|ZEND_INI_SYSTEM) #define ZEND_INI_ALL (ZEND_INI_USER|ZEND_INI_PERDIR|ZEND_INI_SYSTEM)
#ifndef XtOffsetOf
# if defined(CRAY) || (defined(__ARMCC_VERSION) && !defined(LINUX))
# ifdef __STDC__
# define XtOffset(p_type, field) _Offsetof(p_type, field)
# else
# ifdef CRAY2
# define XtOffset(p_type, field) \
(sizeof(int)*((unsigned int)&(((p_type)NULL)->field)))
# else /* !CRAY2 */
# define XtOffset(p_type, field) ((unsigned int)&(((p_type)NULL)->field))
# endif /* !CRAY2 */
# endif /* __STDC__ */
# else /* ! (CRAY || __arm) */
# define XtOffset(p_type, field) \
((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL)))
# endif /* !CRAY */
# ifdef offsetof
# define XtOffsetOf(s_type, field) offsetof(s_type, field)
# else
# define XtOffsetOf(s_type, field) XtOffset(s_type*, field)
# endif
#endif
#define ZEND_INI_MH(name) int name(zend_ini_entry *entry, char *new_value, uint new_value_length, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage TSRMLS_DC) #define ZEND_INI_MH(name) int name(zend_ini_entry *entry, char *new_value, uint new_value_length, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage TSRMLS_DC)
#define ZEND_INI_DISP(name) void name(zend_ini_entry *ini_entry, int type) #define ZEND_INI_DISP(name) void name(zend_ini_entry *ini_entry, int type)

View File

@ -54,6 +54,8 @@ END_EXTERN_C()
#define STR_RELEASE(s) zend_str_release(s) #define STR_RELEASE(s) zend_str_release(s)
#define STR_EMPTY_ALLOC() CG(empty_string) #define STR_EMPTY_ALLOC() CG(empty_string)
#define _STR_HEADER_SIZE XtOffsetOf(zend_string, val)
static zend_always_inline zend_ulong zend_str_hash_val(zend_string *s) static zend_always_inline zend_ulong zend_str_hash_val(zend_string *s)
{ {
if (!s->h) { if (!s->h) {
@ -93,7 +95,7 @@ static zend_always_inline zend_uint zend_str_delref(zend_string *s)
static zend_always_inline zend_string *zend_str_alloc(int len, int persistent) static zend_always_inline zend_string *zend_str_alloc(int len, int persistent)
{ {
zend_string *ret = pemalloc(sizeof(zend_string) + len, persistent); zend_string *ret = pemalloc(_STR_HEADER_SIZE + len + 1, persistent);
GC_REFCOUNT(ret) = 1; GC_REFCOUNT(ret) = 1;
#if 1 #if 1
@ -111,7 +113,7 @@ static zend_always_inline zend_string *zend_str_alloc(int len, int persistent)
static zend_always_inline zend_string *zend_str_safe_alloc(size_t n, size_t m, size_t l, int persistent) static zend_always_inline zend_string *zend_str_safe_alloc(size_t n, size_t m, size_t l, int persistent)
{ {
zend_string *ret = safe_pemalloc(n, m, sizeof(zend_string) + l - 1, persistent); zend_string *ret = safe_pemalloc(n, m, _STR_HEADER_SIZE + l + 1, persistent);
GC_REFCOUNT(ret) = 1; GC_REFCOUNT(ret) = 1;
#if 1 #if 1
@ -161,7 +163,7 @@ static zend_always_inline zend_string *zend_str_realloc(zend_string *s, int len,
ret = STR_ALLOC(len, persistent); ret = STR_ALLOC(len, persistent);
memcpy(ret->val, s->val, (len > s->len ? s->len : len) + 1); memcpy(ret->val, s->val, (len > s->len ? s->len : len) + 1);
} else if (STR_REFCOUNT(s) == 1) { } else if (STR_REFCOUNT(s) == 1) {
ret = perealloc(s, sizeof(zend_string) + len, persistent); ret = perealloc(s, _STR_HEADER_SIZE + len + 1, persistent);
ret->len = len; ret->len = len;
STR_FORGET_HASH_VAL(ret); STR_FORGET_HASH_VAL(ret);
} else { } else {
@ -180,7 +182,7 @@ static zend_always_inline zend_string *zend_str_safe_realloc(zend_string *s, siz
ret = STR_SAFE_ALLOC(n, m, l, persistent); ret = STR_SAFE_ALLOC(n, m, l, persistent);
memcpy(ret->val, s->val, ((n * m) + l > s->len ? s->len : ((n * m) + l)) + 1); memcpy(ret->val, s->val, ((n * m) + l > s->len ? s->len : ((n * m) + l)) + 1);
} else if (STR_REFCOUNT(s) == 1) { } else if (STR_REFCOUNT(s) == 1) {
ret = safe_perealloc(s, n, m, sizeof(zend_string) + l - 1, persistent); ret = safe_perealloc(s, n, m, _STR_HEADER_SIZE + l + 1, persistent);
ret->len = (n * m) + l; ret->len = (n * m) + l;
STR_FORGET_HASH_VAL(ret); STR_FORGET_HASH_VAL(ret);
} else { } else {

View File

@ -336,7 +336,7 @@ zend_string *accel_new_interned_string(zend_string *str TSRMLS_DC)
idx = Z_NEXT(p->val); idx = Z_NEXT(p->val);
} }
if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_string) + str->len) >= if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + str->len + 1) >=
ZCSG(interned_strings_end)) { ZCSG(interned_strings_end)) {
/* no memory, return the same non-interned string */ /* no memory, return the same non-interned string */
return str; return str;
@ -348,7 +348,7 @@ zend_string *accel_new_interned_string(zend_string *str TSRMLS_DC)
ZCSG(interned_strings).nNumOfElements++; ZCSG(interned_strings).nNumOfElements++;
p = ZCSG(interned_strings).arData + idx; p = ZCSG(interned_strings).arData + idx;
p->key = (zend_string*) ZCSG(interned_strings_top); p->key = (zend_string*) ZCSG(interned_strings_top);
ZCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(zend_string) + str->len); ZCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + str->len + 1);
p->h = h; p->h = h;
GC_REFCOUNT(p->key) = 1; GC_REFCOUNT(p->key) = 1;
#if 1 #if 1

View File

@ -40,13 +40,13 @@
STR_RELEASE(str); \ STR_RELEASE(str); \
str = new_str; \ str = new_str; \
} else { \ } else { \
new_str = _zend_shared_memdup((void*)str, sizeof(zend_string) + (str)->len, 0 TSRMLS_CC); \ new_str = _zend_shared_memdup((void*)str, _STR_HEADER_SIZE + (str)->len + 1, 0 TSRMLS_CC); \
STR_RELEASE(str); \ STR_RELEASE(str); \
str = new_str; \ str = new_str; \
} \ } \
} while (0) } while (0)
# define zend_accel_memdup_string(str) \ # define zend_accel_memdup_string(str) \
zend_accel_memdup(str, sizeof(zend_string) + (str)->len) zend_accel_memdup(str, _STR_HEADER_SIZE + (str)->len + 1)
# define zend_accel_store_interned_string(str) do { \ # define zend_accel_store_interned_string(str) do { \
if (!IS_ACCEL_INTERNED(str)) { \ if (!IS_ACCEL_INTERNED(str)) { \
zend_accel_store_string(str); \ zend_accel_store_string(str); \

View File

@ -33,7 +33,7 @@
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
# define ADD_STRING(str) \ # define ADD_STRING(str) \
ADD_DUP_SIZE((str), sizeof(zend_string) + (str)->len) ADD_DUP_SIZE((str), _STR_HEADER_SIZE + (str)->len + 1)
# define ADD_INTERNED_STRING(str, do_free) do { \ # define ADD_INTERNED_STRING(str, do_free) do { \
if (!IS_ACCEL_INTERNED(str)) { \ if (!IS_ACCEL_INTERNED(str)) { \
zend_string *tmp = accel_new_interned_string(str TSRMLS_CC); \ zend_string *tmp = accel_new_interned_string(str TSRMLS_CC); \

View File

@ -45,11 +45,11 @@
#ifdef SMART_STR_USE_REALLOC #ifdef SMART_STR_USE_REALLOC
#define SMART_STR_DO_REALLOC(b, w) do { \ #define SMART_STR_DO_REALLOC(b, w) do { \
(b)->s = erealloc((buf)->s, sizeof(zend_string) + (b)->a); \ (b)->s = erealloc((buf)->s, _STR_HEADER_SIZE + (b)->a + 1); \
} while (0) } while (0)
#else #else
#define SMART_STR_DO_REALLOC(b, w) do { \ #define SMART_STR_DO_REALLOC(b, w) do { \
(b)->s = perealloc((b)->s, sizeof(zend_string) + (b)->a, (w)); \ (b)->s = perealloc((b)->s, _STR_HEADER_SIZE + (b)->a + 1, (w)); \
} while (0) } while (0)
#endif #endif

View File

@ -24,7 +24,7 @@ echo "*** Testing str_pad() function: with large value for for 'pad_length' argu
//defining '$input' argument //defining '$input' argument
$input = "Test string"; $input = "Test string";
$pad_length = PHP_INT_MAX - 20 + 1; /* sizeof(zend_string) is 20, 1 character is included in zend_string structure itself */ $pad_length = PHP_INT_MAX - 16; /* zend_string header is 16 bytes */
var_dump( str_pad($input, $pad_length) ); var_dump( str_pad($input, $pad_length) );
?> ?>