3232
3333#include "hash_arginfo.h"
3434
35+ #ifdef PHP_WIN32
36+ # define __alignof__ __alignof
37+ #else
38+ # ifndef HAVE_ALIGNOF
39+ # include <stddef.h>
40+ # define __alignof__ (type ) offsetof (struct { char c; type member;}, member)
41+ # endif
42+ #endif
43+
3544HashTable php_hash_hashtable ;
3645zend_class_entry * php_hashcontext_ce ;
3746static zend_object_handlers php_hashcontext_handlers ;
@@ -115,20 +124,36 @@ PHP_HASH_API int php_hash_copy(const void *ops, void *orig_context, void *dest_c
115124/* }}} */
116125
117126
118- static size_t parse_serialize_spec (const char * * specp , size_t * pos , size_t * sz ) {
119- size_t count ;
127+ static inline size_t align_to (size_t pos , size_t alignment ) {
128+ size_t offset = pos & (alignment - 1 );
129+ return pos + (offset ? alignment - offset : 0 );
130+ }
131+
132+ static size_t parse_serialize_spec (const char * * specp , size_t * pos , size_t * sz ,
133+ size_t * max_alignment ) {
134+ size_t count , alignment ;
120135 const char * spec = * specp ;
136+ /* parse size */
121137 if (* spec == 's' ) {
122138 * sz = 2 ;
139+ alignment = __alignof__(uint16_t ); /* usually 2 */
123140 } else if (* spec == 'l' ) {
124141 * sz = 4 ;
142+ alignment = __alignof__(uint32_t ); /* usually 4 */
125143 } else if (* spec == 'q' ) {
126144 * sz = 8 ;
145+ alignment = __alignof__(uint64_t ); /* usually 8 */
127146 } else if (* spec == 'i' ) {
128147 * sz = sizeof (int );
148+ alignment = __alignof__(int ); /* usually 4 */
129149 } else {
130150 * sz = 1 ;
151+ alignment = 1 ;
131152 }
153+ /* process alignment */
154+ * pos = align_to (* pos , alignment );
155+ * max_alignment = * max_alignment < alignment ? alignment : * max_alignment ;
156+ /* parse count */
132157 ++ spec ;
133158 if (isdigit ((unsigned char ) * spec )) {
134159 count = 0 ;
@@ -140,10 +165,6 @@ static size_t parse_serialize_spec(const char **specp, size_t *pos, size_t *sz)
140165 count = 1 ;
141166 }
142167 * specp = spec ;
143- // alignment
144- if (* sz > 1 && (* pos & (* sz - 1 )) != 0 ) {
145- * pos += * sz - (* pos & (* sz - 1 ));
146- }
147168 return count ;
148169}
149170
@@ -184,6 +205,7 @@ static void one_to_buffer(size_t sz, unsigned char *buf, uint64_t val) {
184205 l[COUNT] -- serialize COUNT 32-bit integers
185206 q[COUNT] -- serialize COUNT 64-bit integers
186207 i[COUNT] -- serialize COUNT `int`s
208+ -[COUNT] -- skip COUNT bytes
187209 . (must be last character) -- assert that the hash context has exactly
188210 this size
189211 Example: "llllllb64l16." is the spec for an MD5 context: 6 32-bit
@@ -198,14 +220,14 @@ static void one_to_buffer(size_t sz, unsigned char *buf, uint64_t val) {
198220
199221PHP_HASH_API int php_hash_serialize_spec (const php_hashcontext_object * hash , zend_long * magic , zval * zv , const char * spec ) /* {{{ */
200222{
201- size_t pos = 0 , sz , count ;
223+ size_t pos = 0 , max_alignment = 1 , sz , count ;
202224 unsigned char * buf = (unsigned char * ) hash -> context ;
203225 zval tmp ;
204226 * magic = PHP_HASH_SERIALIZE_MAGIC_SPEC ;
205227 array_init (zv );
206228 while (* spec != '\0' && * spec != '.' ) {
207229 char specch = * spec ;
208- count = parse_serialize_spec (& spec , & pos , & sz );
230+ count = parse_serialize_spec (& spec , & pos , & sz , & max_alignment );
209231 if (pos + count * sz > hash -> ops -> context_size ) {
210232 return FAILURE ;
211233 }
@@ -229,7 +251,7 @@ PHP_HASH_API int php_hash_serialize_spec(const php_hashcontext_object *hash, zen
229251 }
230252 }
231253 }
232- if (* spec == '.' && pos != hash -> ops -> context_size ) {
254+ if (* spec == '.' && align_to ( pos , max_alignment ) != hash -> ops -> context_size ) {
233255 return FAILURE ;
234256 }
235257 return SUCCESS ;
@@ -244,15 +266,15 @@ PHP_HASH_API int php_hash_serialize_spec(const php_hashcontext_object *hash, zen
244266
245267PHP_HASH_API int php_hash_unserialize_spec (php_hashcontext_object * hash , zend_long magic , const zval * zv , const char * spec ) /* {{{ */
246268{
247- size_t pos = 0 , sz , count , j = 0 ;
269+ size_t pos = 0 , max_alignment = 1 , sz , count , j = 0 ;
248270 unsigned char * buf = (unsigned char * ) hash -> context ;
249271 zval * elt ;
250272 if (magic != PHP_HASH_SERIALIZE_MAGIC_SPEC || Z_TYPE_P (zv ) != IS_ARRAY ) {
251273 return FAILURE ;
252274 }
253275 while (* spec != '\0' && * spec != '.' ) {
254276 char specch = * spec ;
255- count = parse_serialize_spec (& spec , & pos , & sz );
277+ count = parse_serialize_spec (& spec , & pos , & sz , & max_alignment );
256278 if (pos + count * sz > hash -> ops -> context_size ) {
257279 return -999 ;
258280 }
@@ -289,7 +311,7 @@ PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, zend_lo
289311 }
290312 }
291313 }
292- if (* spec == '.' && pos != hash -> ops -> context_size ) {
314+ if (* spec == '.' && align_to ( pos , max_alignment ) != hash -> ops -> context_size ) {
293315 return -999 ;
294316 }
295317 return SUCCESS ;
0 commit comments