32
32
33
33
#include "hash_arginfo.h"
34
34
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
+
35
44
HashTable php_hash_hashtable ;
36
45
zend_class_entry * php_hashcontext_ce ;
37
46
static 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
115
124
/* }}} */
116
125
117
126
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 ;
120
135
const char * spec = * specp ;
136
+ /* parse size */
121
137
if (* spec == 's' ) {
122
138
* sz = 2 ;
139
+ alignment = __alignof__(uint16_t ); /* usually 2 */
123
140
} else if (* spec == 'l' ) {
124
141
* sz = 4 ;
142
+ alignment = __alignof__(uint32_t ); /* usually 4 */
125
143
} else if (* spec == 'q' ) {
126
144
* sz = 8 ;
145
+ alignment = __alignof__(uint64_t ); /* usually 8 */
127
146
} else if (* spec == 'i' ) {
128
147
* sz = sizeof (int );
148
+ alignment = __alignof__(int ); /* usually 4 */
129
149
} else {
130
150
* sz = 1 ;
151
+ alignment = 1 ;
131
152
}
153
+ /* process alignment */
154
+ * pos = align_to (* pos , alignment );
155
+ * max_alignment = * max_alignment < alignment ? alignment : * max_alignment ;
156
+ /* parse count */
132
157
++ spec ;
133
158
if (isdigit ((unsigned char ) * spec )) {
134
159
count = 0 ;
@@ -140,10 +165,6 @@ static size_t parse_serialize_spec(const char **specp, size_t *pos, size_t *sz)
140
165
count = 1 ;
141
166
}
142
167
* specp = spec ;
143
- // alignment
144
- if (* sz > 1 && (* pos & (* sz - 1 )) != 0 ) {
145
- * pos += * sz - (* pos & (* sz - 1 ));
146
- }
147
168
return count ;
148
169
}
149
170
@@ -184,6 +205,7 @@ static void one_to_buffer(size_t sz, unsigned char *buf, uint64_t val) {
184
205
l[COUNT] -- serialize COUNT 32-bit integers
185
206
q[COUNT] -- serialize COUNT 64-bit integers
186
207
i[COUNT] -- serialize COUNT `int`s
208
+ -[COUNT] -- skip COUNT bytes
187
209
. (must be last character) -- assert that the hash context has exactly
188
210
this size
189
211
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) {
198
220
199
221
PHP_HASH_API int php_hash_serialize_spec (const php_hashcontext_object * hash , zend_long * magic , zval * zv , const char * spec ) /* {{{ */
200
222
{
201
- size_t pos = 0 , sz , count ;
223
+ size_t pos = 0 , max_alignment = 1 , sz , count ;
202
224
unsigned char * buf = (unsigned char * ) hash -> context ;
203
225
zval tmp ;
204
226
* magic = PHP_HASH_SERIALIZE_MAGIC_SPEC ;
205
227
array_init (zv );
206
228
while (* spec != '\0' && * spec != '.' ) {
207
229
char specch = * spec ;
208
- count = parse_serialize_spec (& spec , & pos , & sz );
230
+ count = parse_serialize_spec (& spec , & pos , & sz , & max_alignment );
209
231
if (pos + count * sz > hash -> ops -> context_size ) {
210
232
return FAILURE ;
211
233
}
@@ -229,7 +251,7 @@ PHP_HASH_API int php_hash_serialize_spec(const php_hashcontext_object *hash, zen
229
251
}
230
252
}
231
253
}
232
- if (* spec == '.' && pos != hash -> ops -> context_size ) {
254
+ if (* spec == '.' && align_to ( pos , max_alignment ) != hash -> ops -> context_size ) {
233
255
return FAILURE ;
234
256
}
235
257
return SUCCESS ;
@@ -244,15 +266,15 @@ PHP_HASH_API int php_hash_serialize_spec(const php_hashcontext_object *hash, zen
244
266
245
267
PHP_HASH_API int php_hash_unserialize_spec (php_hashcontext_object * hash , zend_long magic , const zval * zv , const char * spec ) /* {{{ */
246
268
{
247
- size_t pos = 0 , sz , count , j = 0 ;
269
+ size_t pos = 0 , max_alignment = 1 , sz , count , j = 0 ;
248
270
unsigned char * buf = (unsigned char * ) hash -> context ;
249
271
zval * elt ;
250
272
if (magic != PHP_HASH_SERIALIZE_MAGIC_SPEC || Z_TYPE_P (zv ) != IS_ARRAY ) {
251
273
return FAILURE ;
252
274
}
253
275
while (* spec != '\0' && * spec != '.' ) {
254
276
char specch = * spec ;
255
- count = parse_serialize_spec (& spec , & pos , & sz );
277
+ count = parse_serialize_spec (& spec , & pos , & sz , & max_alignment );
256
278
if (pos + count * sz > hash -> ops -> context_size ) {
257
279
return -999 ;
258
280
}
@@ -289,7 +311,7 @@ PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, zend_lo
289
311
}
290
312
}
291
313
}
292
- if (* spec == '.' && pos != hash -> ops -> context_size ) {
314
+ if (* spec == '.' && align_to ( pos , max_alignment ) != hash -> ops -> context_size ) {
293
315
return -999 ;
294
316
}
295
317
return SUCCESS ;
0 commit comments