File Coverage

srl_decoder.c
Criterion Covered Total %
statement 602 718 83.8
branch 459 998 45.9
condition n/a
subroutine n/a
pod n/a
total 1061 1716 61.8


line stmt bran cond sub pod time code
1             /* Must be defined before including Perl header files or we slow down by 2x! */
2             #define PERL_NO_GET_CONTEXT
3              
4             #ifdef __cplusplus
5             extern "C" {
6             #endif
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10             #define NEED_newSV_type
11             #define NEED_newSVpvn_flags
12             #include "ppport.h"
13             #ifdef __cplusplus
14             }
15             #endif
16              
17             #ifndef PERL_VERSION
18             # include
19             # if !(defined(PERL_VERSION) || (PERL_SUBVERSION > 0 && defined(PATCHLEVEL)))
20             # include
21             # endif
22             # define PERL_REVISION 5
23             # define PERL_VERSION PATCHLEVEL
24             # define PERL_SUBVERSION PERL_SUBVERSION
25             #endif
26             #if PERL_VERSION < 8
27             # define PERL_MAGIC_qr 'r' /* precompiled qr// regex */
28             # define BFD_Svs_SMG_OR_RMG SVs_RMG
29             #elif ((PERL_VERSION==8) && (PERL_SUBVERSION >= 1) || (PERL_VERSION>8))
30             # define BFD_Svs_SMG_OR_RMG SVs_SMG
31             # define MY_PLACEHOLDER PL_sv_placeholder
32             #else
33             # define BFD_Svs_SMG_OR_RMG SVs_RMG
34             # define MY_PLACEHOLDER PL_sv_undef
35             #endif
36             #if (((PERL_VERSION == 9) && (PERL_SUBVERSION >= 4)) || (PERL_VERSION > 9))
37             # define NEW_REGEX_ENGINE 1
38             #endif
39             #if (((PERL_VERSION == 8) && (PERL_SUBVERSION >= 1)) || (PERL_VERSION > 8))
40             #define MY_CAN_FIND_PLACEHOLDERS
41             #define HAS_SV2OBJ
42             #endif
43             #if (PERL_VERSION < 10)
44             # define FIXUP_RITER 1
45             #endif
46             #if (PERL_VERSION >= 10)
47             # define FAST_IV 1
48             #endif
49             #define DEFAULT_MAX_RECUR_DEPTH 10000
50              
51             #if !defined(HAVE_CSNAPPY)
52             # include "snappy/csnappy_decompress.c"
53             #endif
54              
55             #include "srl_decoder.h"
56              
57             #include "srl_common.h"
58             #include "ptable.h"
59             #include "srl_reader.h"
60             #include "srl_reader_error.h"
61             #include "srl_reader_varint.h"
62             #include "srl_reader_misc.h"
63             #include "srl_reader_decompress.h"
64             #include "srl_protocol.h"
65             #include "srl_taginfo.h"
66              
67             /* 5.8.8 and earlier have a nasty bug in their handling of overloading:
68             * The overload-flag is set on the referer of the blessed object instead of
69             * the referent. That means that our late-bless logic breaks for
70             * multiply-occurring objects.
71             * So for 5.8.8 and earlier, the easiest workaround is to bless as we go
72             * instead of blessing at the end of a decode run. Additionally, on repeatedly
73             * encountered objects (REFP), we have to check the stash of the referent for
74             * overloadedness and set the OVERLOAD flag (AMAGIC_on) on the NEW referer.
75             *
76             * Details on the perl bug in perl589delta.pod,
77             * see "Reblessing overloaded objects now works".
78             *
79             * This is potentially a security problem (destructors!), but we really need
80             * this to work on 5.8.5 for now, so let's make it work.
81             * Another way of making it work might be to keep track of all occurrences
82             * of objects and fix them up afterwards. That seems even more intrusive.
83             * Please prove us wrong, though, since it's semantically a better fix.
84             *
85             * --Eric and Steffen
86             */
87             #if ((PERL_VERSION == 8) && (PERL_SUBVERSION >= 9) || (PERL_VERSION > 8))
88             # define USE_588_WORKAROUND 0
89             #else
90             # define USE_588_WORKAROUND 1
91             #endif
92              
93             /* predeclare all our subs so we have one definitive authority for their signatures */
94             SRL_STATIC_INLINE SV *srl_fetch_item(pTHX_ srl_decoder_t *dec, UV item, const char * const tag_name);
95              
96             /* these three are "Public" */
97             srl_decoder_t *srl_build_decoder_struct(pTHX_ HV *opt, sv_with_hash *options); /* constructor - called from ->new() */
98             void srl_destroy_decoder(pTHX_ srl_decoder_t *dec); /* destructor - called from ->DESTROY() */
99             void srl_decoder_destructor_hook(pTHX_ void *p); /* destructor hook - called automagically */
100              
101             /* the top level components of the decode process - called by srl_decode_into() */
102             /* srl_begin_decoding: set up the decoder to handle a given var */
103             SRL_STATIC_INLINE srl_decoder_t *srl_begin_decoding(pTHX_ srl_decoder_t *dec, SV *src, UV start_offset);
104             SRL_STATIC_INLINE void srl_read_header(pTHX_ srl_decoder_t *dec, SV *header_user_data); /* read/validate header */
105             SRL_STATIC_INLINE void srl_read_single_value(pTHX_ srl_decoder_t *dec, SV* into, SV** container); /* main recursive dump routine */
106             SRL_STATIC_INLINE void srl_finalize_structure(pTHX_ srl_decoder_t *dec); /* optional finalize structure logic */
107             SRL_STATIC_INLINE void srl_clear_decoder(pTHX_ srl_decoder_t *dec); /* clean up decoder after a dump */
108              
109             /* the internal routines to handle each kind of object we have to deserialize */
110             SRL_STATIC_INLINE void srl_read_copy(pTHX_ srl_decoder_t *dec, SV* into);
111              
112             SRL_STATIC_INLINE void srl_read_hash(pTHX_ srl_decoder_t *dec, SV* into, U8 tag);
113             SRL_STATIC_INLINE void srl_read_array(pTHX_ srl_decoder_t *dec, SV* into, U8 tag);
114             SRL_STATIC_INLINE void srl_read_regexp(pTHX_ srl_decoder_t *dec, SV* into);
115              
116             SRL_STATIC_INLINE void srl_read_refp(pTHX_ srl_decoder_t *dec, SV* into);
117             SRL_STATIC_INLINE void srl_read_refn(pTHX_ srl_decoder_t *dec, SV* into);
118             SRL_STATIC_INLINE void srl_read_weaken(pTHX_ srl_decoder_t *dec, SV* into);
119             SRL_STATIC_INLINE void srl_read_long_double(pTHX_ srl_decoder_t *dec, SV* into);
120             SRL_STATIC_INLINE void srl_read_double(pTHX_ srl_decoder_t *dec, SV* into);
121             SRL_STATIC_INLINE void srl_read_float(pTHX_ srl_decoder_t *dec, SV* into);
122             SRL_STATIC_INLINE void srl_read_string(pTHX_ srl_decoder_t *dec, int is_utf8, SV* into);
123             SRL_STATIC_INLINE void srl_read_varint_into(pTHX_ srl_decoder_t *dec, SV* into, SV** container, const U8 *track_it);
124             SRL_STATIC_INLINE void srl_read_zigzag_into(pTHX_ srl_decoder_t *dec, SV* into, SV** container, const U8 *track_it);
125             SRL_STATIC_INLINE void srl_read_reserved(pTHX_ srl_decoder_t *dec, U8 tag, SV* into);
126             SRL_STATIC_INLINE void srl_read_object(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag, int read_class_name_only);
127             SRL_STATIC_INLINE void srl_read_objectv(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag);
128              
129             SRL_STATIC_INLINE void srl_track_sv(pTHX_ srl_decoder_t *dec, const U8 *track_pos, SV *sv);
130             SRL_STATIC_INLINE void srl_read_frozen_object(pTHX_ srl_decoder_t *dec, HV *class_stash, SV *into);
131             SRL_STATIC_INLINE SV * srl_follow_refp_alias_reference(pTHX_ srl_decoder_t *dec, UV offset);
132             SRL_STATIC_INLINE AV * srl_follow_objectv_reference(pTHX_ srl_decoder_t *dec, UV offset);
133              
134             /* FIXME unimplemented!!! */
135             SRL_STATIC_INLINE SV *srl_read_extend(pTHX_ srl_decoder_t *dec, SV* into);
136              
137             #define DEPTH_INCREMENT(dec) STMT_START { \
138             if (expect_false(++dec->recursion_depth > dec->max_recursion_depth)) { \
139             SRL_RDR_ERRORf1(dec->pbuf, "Reached recursion limit (%"UVuf") during deserialization", \
140             (UV)dec->max_recursion_depth); \
141             } \
142             } STMT_END
143              
144             #define DEPTH_DECREMENT(dec) dec->recursion_depth--
145              
146             #define IS_SRL_HDR_ARRAYREF(tag) (((tag) & SRL_HDR_ARRAYREF) == SRL_HDR_ARRAYREF)
147             #define IS_SRL_HDR_HASHREF(tag) (((tag) & SRL_HDR_HASHREF) == SRL_HDR_HASHREF)
148             #define IS_SRL_HDR_SHORT_BINARY(tag) (((tag) & SRL_HDR_SHORT_BINARY_LOW) == SRL_HDR_SHORT_BINARY_LOW)
149             #define SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag) ((tag) & SRL_MASK_SHORT_BINARY_LEN)
150              
151              
152             #define SRL_ASSERT_REF_PTR_TABLES(dec) STMT_START { \
153             if (expect_false( !(dec)->ref_stashes )) { \
154             (dec)->ref_stashes = PTABLE_new(); \
155             (dec)->ref_bless_av = PTABLE_new(); \
156             } \
157             } STMT_END
158              
159             #define SRL_sv_set_rv_to(into,referent) \
160             STMT_START { \
161             SRL_prepare_SV_for_RV(into); \
162             SvTEMP_off(referent); \
163             SvRV_set(into, referent); \
164             SvROK_on(into); \
165             } STMT_END
166              
167             STATIC void
168 0           srl_ptable_debug_callback(PTABLE_ENTRY_t *e)
169             {
170             dTHX;
171 0           printf("KEY=%"UVuf"\nVALUE:\n", (UV)e->key);
172 0           sv_dump((SV *)e->value);
173 0           printf("\n");
174 0           }
175              
176             SRL_STATIC_INLINE void
177             srl_ptable_debug_dump(pTHX_ PTABLE_t *tbl)
178             {
179             PTABLE_debug_dump(tbl, srl_ptable_debug_callback);
180             }
181              
182             #define my_hv_fetchs(he,val,opt,idx) STMT_START { \
183             he = hv_fetch_ent(opt, options[idx].sv, 0, options[idx].hash); \
184             if (he) \
185             val= HeVAL(he); \
186             else \
187             val= NULL; \
188             } STMT_END
189              
190             /* Multiple places in this file that want to use srl_read_varint_uv_length
191             * but don't have a buffer struct handy. */
192             SRL_STATIC_INLINE UV
193 0           S_read_varint_uv_length_char_ptr(pTHX_ const unsigned char **from, const unsigned char *end, const char * const errstr)
194             {
195             UV rv;
196             srl_reader_buffer_t buf;
197 0           buf.pos = *from;
198 0           buf.end = end;
199 0           buf.start = NULL; /* meh */
200 0           rv = srl_read_varint_uv_length(aTHX_ &buf, errstr);
201 0           *from = buf.pos;
202 0           return rv;
203             }
204              
205              
206             /* PUBLIC ROUTINES */
207              
208             /* Builds the C-level configuration and state struct.
209             * Automatically freed at scope boundary. */
210             srl_decoder_t *
211 179507           srl_build_decoder_struct(pTHX_ HV *opt, sv_with_hash *options)
212             {
213             srl_decoder_t *dec;
214             SV *val;
215             HE *he;
216              
217 179507           Newxz(dec, 1, srl_decoder_t);
218              
219 179507           dec->ref_seenhash = PTABLE_new();
220 179507           dec->max_recursion_depth = DEFAULT_MAX_RECUR_DEPTH;
221 179507           dec->max_num_hash_entries = 0; /* 0 == any number */
222              
223 179507           SRL_RDR_CLEAR(&dec->buf);
224 179507           dec->pbuf = &dec->buf;
225              
226             /* load options */
227 179507 100         if (opt != NULL) {
228 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_REFUSE_SNAPPY);
229 179398 100         if ( val && SvTRUE(val) )
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
230 2           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_REFUSE_SNAPPY);
231              
232 179398 50         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_REFUSE_ZLIB);
233 179398 50         if ( val && SvTRUE(val) )
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
234 0           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_REFUSE_ZLIB);
235              
236 179398 50         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_REFUSE_ZSTD);
237 179398 50         if ( val && SvTRUE(val) )
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
238 0           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_REFUSE_ZSTD);
239              
240 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_REFUSE_OBJECTS);
241 179398 100         if ( val && SvTRUE(val) )
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
242 2           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_REFUSE_OBJECTS);
243              
244 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_NO_BLESS_OBJECTS);
245 179398 100         if ( val && SvTRUE(val) )
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
246 1           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_NO_BLESS_OBJECTS);
247              
248 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_VALIDATE_UTF8);
249 179398 100         if ( val && SvTRUE(val) )
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
250 12           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_VALIDATE_UTF8);
251              
252 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_MAX_RECURSION_DEPTH);
253 179398 100         if ( val && SvTRUE(val) )
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
254 2 50         dec->max_recursion_depth = SvUV(val);
255              
256 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_MAX_NUM_HASH_ENTRIES);
257 179398 100         if ( val && SvTRUE(val) )
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
258 5 50         dec->max_num_hash_entries = SvUV(val);
259              
260 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_DESTRUCTIVE_INCREMENTAL);
261 179398 100         if ( val && SvTRUE(val) )
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
262 2           SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_DESTRUCTIVE_INCREMENTAL);
263              
264             /* see if they want us to alias varints, value is an unsigned integer.
265             * setting it to a true value smaller than 16 is the same as
266             * using the "alias_smallint" option. Setting it to a true value larger
267             * than 15 enables aliasing of smallints, and implies "alias_smallint" as
268             * well. */
269 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_ALIAS_VARINT_UNDER);
270 179398 100         if ( val && SvTRUE(val)) {
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
271             /* if they use this then they automatically imply doing it for
272             * smallint as well */
273 2           SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT);
274 2           SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_ALIAS_VARINT);
275 2 50         if (SvUV(val) < 16) {
    50          
276             /* too small, just enable for SMALLINT (POS/NEG)*/
277 0           dec->alias_varint_under= 16;
278             } else {
279             /* larger than POS/NEG range, also alias some VARINTs */
280             /* anything smaller than this number will be aliased */
281 2 50         dec->alias_varint_under= SvUV(val);
282             }
283             /* create the alias cache */
284 2           dec->alias_cache= newAV();
285             }
286             /* they can enable aliasing of SMALLINT's alone */
287 179398 100         if ( !SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT) ) {
288 179396 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_ALIAS_SMALLINT);
289 179396 100         if (val && SvTRUE(val))
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
290             {
291             /* set the flag */
292 1           SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT);
293             /* create the alias cache */
294 1           dec->alias_cache= newAV();
295 1           dec->alias_varint_under=16;
296             }
297             }
298              
299 179398 100         if (dec->alias_varint_under) {
300             /* extend it to the right size 16 for NEG,
301             * dec->alias_varint_under is at least 15, and 1 more for zero,
302             * so we allocate enough for POS/NEG as well as for the additional varints*/
303 3           av_extend(dec->alias_cache, 16 + dec->alias_varint_under);
304 3           AvFILLp(dec->alias_cache)= 16 + dec->alias_varint_under - 1; /* remove 1 as this is $#ary */
305             }
306              
307             /* check if they want us to use &PL_sv_undef for SRL_HEADER_UNDEF
308             * even if this might break referential integrity. */
309 179398 50         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_USE_UNDEF);
310 179398 50         if ( val && SvTRUE(val))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
311 0           SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_USE_UNDEF);
312              
313             /* check if they want us to set all SVs readonly. */
314 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_SET_READONLY);
315 179398 100         if ( val && SvTRUE(val))
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
316 12445           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_SET_READONLY);
317              
318             /* check if they want us to set normal scalars readonly. */
319 179398 100         my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_SET_READONLY_SCALARS);
320 179398 100         if ( val && SvTRUE(val))
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
321 6           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_SET_READONLY_SCALARS);
322              
323             }
324 179507 100         dec->flags_readonly= SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_SET_READONLY ) ? 1 :
    100          
325 167062           SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_SET_READONLY_SCALARS) ? 2 :
326             0;
327 179507           return dec;
328             }
329              
330             /* Clone a decoder whilst resetting ephemeral state on the clone. */
331             SRL_STATIC_INLINE srl_decoder_t *
332 1           srl_build_decoder_struct_alike(pTHX_ srl_decoder_t *proto)
333             {
334             srl_decoder_t *dec;
335              
336 1           Newxz(dec, 1, srl_decoder_t);
337              
338 1           dec->ref_seenhash = PTABLE_new();
339 1           dec->max_recursion_depth = proto->max_recursion_depth;
340 1           dec->max_num_hash_entries = proto->max_num_hash_entries;
341              
342 1 50         if (proto->alias_cache) {
343 0           dec->alias_cache = proto->alias_cache;
344 0           SvREFCNT_inc(dec->alias_cache);
345             }
346              
347 1           SRL_RDR_CLEAR(&dec->buf);
348 1           dec->pbuf = &dec->buf;
349 1           dec->flags = proto->flags;
350 1           SRL_DEC_RESET_VOLATILE_FLAGS(dec);
351              
352 1           return dec;
353             }
354              
355             /* Explicit destructor */
356             void
357 179508           srl_destroy_decoder(pTHX_ srl_decoder_t *dec)
358             {
359 179508           PTABLE_free(dec->ref_seenhash);
360 179508 100         if (dec->ref_stashes) {
361 5223           PTABLE_free(dec->ref_stashes);
362 5223           PTABLE_free(dec->ref_bless_av);
363             }
364 179508 100         if (dec->weakref_av) {
365 3           SvREFCNT_dec(dec->weakref_av);
366 3           dec->weakref_av = NULL;
367             }
368 179508 50         if (dec->ref_thawhash)
369 0           PTABLE_free(dec->ref_thawhash);
370 179508 100         if (dec->alias_cache)
371 3           SvREFCNT_dec(dec->alias_cache);
372 179508           Safefree(dec);
373 179508           }
374              
375             /* This is fired when we exit the Perl pseudo-block.
376             * It frees our decoder and all. Put decoder-level cleanup
377             * logic here so that we can simply use croak/longjmp for
378             * exception handling. Makes life vastly easier!
379             */
380             void
381 865140           srl_decoder_destructor_hook(pTHX_ void *p)
382             {
383 865140           srl_decoder_t *dec = (srl_decoder_t *)p;
384              
385             /* Only free decoder if not for reuse */
386 865140 100         if (!SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_REUSE)) {
387 179345           srl_destroy_decoder(aTHX_ dec);
388             }
389             else {
390             /* Clear instead - decoder reused */
391 685795           srl_clear_decoder(aTHX_ dec);
392             }
393 865140           }
394              
395             /* Logic shared by the various decoder entry points. */
396             SRL_STATIC_INLINE void
397 702660           srl_decode_into_internal(pTHX_ srl_decoder_t *origdec, SV *src, SV *header_into, SV *body_into, UV start_offset)
398             {
399             srl_decoder_t *dec;
400              
401             assert(origdec != NULL);
402 702660           dec = srl_begin_decoding(aTHX_ origdec, src, start_offset);
403 702660           srl_read_header(aTHX_ dec, header_into);
404 702651 100         if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_DECOMPRESS_SNAPPY) )) {
405 58322           dec->bytes_consumed = srl_decompress_body_snappy(aTHX_ dec->pbuf, dec->encoding_flags, NULL);
406 58322           origdec->bytes_consumed = dec->bytes_consumed;
407 644329 100         } else if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_DECOMPRESS_ZLIB) )) {
408 20140           dec->bytes_consumed = srl_decompress_body_zlib(aTHX_ dec->pbuf, NULL);
409 20140           origdec->bytes_consumed = dec->bytes_consumed;
410 624189 100         } else if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_DECOMPRESS_ZSTD) )) {
411 9536           dec->bytes_consumed = srl_decompress_body_zstd(aTHX_ dec->pbuf, NULL);
412 9536           origdec->bytes_consumed = dec->bytes_consumed;
413             }
414              
415             /* this function *MUST* be called right after srl_decompress* functions */
416 702651 100         SRL_RDR_UPDATE_BODY_POS(dec->pbuf, dec->proto_version);
417              
418             /* The actual document body deserialization: */
419 702651           srl_read_single_value(aTHX_ dec, body_into, NULL);
420 702637 100         if (expect_false(SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_NEEDS_FINALIZE))) {
421 20164           srl_finalize_structure(aTHX_ dec);
422             }
423              
424             /* If we aren't reading from a decompressed buffer we have to remember the number
425             * of bytes used for the user to query. */
426 702637 100         if (dec->bytes_consumed == 0) {
427 614638           dec->bytes_consumed = dec->buf.pos - dec->buf.start;
428 614638           origdec->bytes_consumed = dec->bytes_consumed;
429             }
430              
431 702637 100         if (SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_DESTRUCTIVE_INCREMENTAL)) {
432             STRLEN len;
433 10 50         char *pv= SvPV(src,len);
434             /* check the length here? do something different if the string is now exhausted? */
435 10           sv_chop(src, pv + dec->bytes_consumed);
436             }
437              
438 702637           srl_clear_decoder(aTHX_ dec);
439 702637           }
440              
441             /* This is the main routine to deserialize just the header of a document. */
442             SV *
443 162480           srl_decode_header_into(pTHX_ srl_decoder_t *origdec, SV *src, SV* header_into, UV start_offset)
444             {
445             srl_decoder_t *dec;
446             assert(origdec != NULL);
447 162480           dec = srl_begin_decoding(aTHX_ origdec, src, start_offset);
448 162480 50         if (header_into == NULL)
449 0           header_into = sv_newmortal();
450 162480           srl_read_header(aTHX_ dec, header_into);
451 162480           return header_into;
452             }
453              
454             /* this SHOULD be newSV_type(SVt_NULL) but newSV(0) is faster :-( */
455             #if 1
456             #define FRESH_SV() newSV(0)
457             #else
458             #define FRESH_SV() newSV_type(SVt_NULL);
459             #endif
460              
461             /* This is the main routine to deserialize a Sereal document
462             * w/o data in header. */
463             SV *
464 702660           srl_decode_into(pTHX_ srl_decoder_t *dec, SV *src, SV* body_into, UV start_offset)
465             {
466 702660 100         if (expect_true(!body_into))
467 179288           body_into= sv_2mortal(FRESH_SV());
468 702660           srl_decode_into_internal(aTHX_ dec, src, NULL, body_into, start_offset);
469 702637           return body_into;
470             }
471              
472             /* This is the main routine to deserialize Sereal document body
473             * and header all at once. */
474             void
475 0           srl_decode_all_into(pTHX_ srl_decoder_t *dec, SV *src, SV *header_into, SV *body_into, UV start_offset)
476             {
477             assert(header_into != NULL);
478             assert(body_into != NULL);
479 0           (void)srl_decode_into_internal(aTHX_ dec, src, header_into, body_into, start_offset);
480 0           }
481              
482              
483             /* TOP LEVEL PRIVATE ROUTINES */
484              
485             SRL_STATIC_INLINE void
486 1388432           srl_clear_decoder(pTHX_ srl_decoder_t *dec)
487             {
488 1388432 100         if (dec->buf.start == dec->buf.end)
489 523305           return;
490              
491 865127           srl_clear_decoder_body_state(aTHX_ dec);
492 865127           SRL_DEC_RESET_VOLATILE_FLAGS(dec);
493 865127           dec->buf.body_pos = dec->buf.start = dec->buf.end = dec->buf.pos = dec->save_pos = NULL;
494             }
495              
496             void
497 1027487           srl_clear_decoder_body_state(pTHX_ srl_decoder_t *dec)
498             {
499 1027487           SRL_DEC_UNSET_OPTION(dec, SRL_F_DECODER_NEEDS_FINALIZE);
500              
501 1027487 100         if (dec->weakref_av)
502 15           av_clear(dec->weakref_av);
503              
504 1027487           PTABLE_clear(dec->ref_seenhash);
505 1027487 100         if (dec->ref_stashes) {
506 778326           PTABLE_clear(dec->ref_stashes);
507 778326           PTABLE_clear(dec->ref_bless_av);
508             }
509              
510 1027487           dec->recursion_depth = 0;
511 1027487           }
512              
513             SRL_STATIC_INLINE srl_decoder_t *
514 865140           srl_begin_decoding(pTHX_ srl_decoder_t *dec, SV *src, UV start_offset)
515             {
516             STRLEN len;
517             unsigned char *tmp;
518              
519             /* Check whether decoder is in use and create a new one on the
520             * fly if necessary. Should only happen in edge cases such as
521             * a THAW hook calling back into the same decoder. */
522 865140 100         if (SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_DIRTY)) {
523 1           srl_decoder_t * const proto = dec;
524 1           dec = srl_build_decoder_struct_alike(aTHX_ proto);
525 1           SRL_DEC_UNSET_OPTION(dec, SRL_F_DECODER_REUSE);
526             }
527              
528             /* Needs to be before setting DIRTY because DIRTY is volatile. */
529 865140           SRL_DEC_RESET_VOLATILE_FLAGS(dec);
530              
531             /* Set to being in use. */;
532 865140           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_DIRTY);
533              
534             /* Register our structure for destruction on scope exit */
535 865140           SAVEDESTRUCTOR_X(&srl_decoder_destructor_hook, (void *)dec);
536              
537 865140 100         if (SvUTF8(src)) {
538             /* If we are being asked to decode a utf8-on string then we
539             * make a mortal copy, and then try to downgrade the copy.
540             * The downgrade will croak if it cannot successfully downgrade
541             * the buffer. If it is sucessful then decode the downgraded
542             * copy.
543             * Note, we do not make the copy when we are in destructive parsing mode
544             * as we then are expected to modify the original string.
545             */
546 3 100         if ( ! SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_DESTRUCTIVE_INCREMENTAL) ) {
547 2           src= sv_mortalcopy(src);
548             }
549 3           sv_utf8_downgrade(src, 0);
550             }
551              
552 865140 50         tmp = (unsigned char*)SvPV(src, len);
553 865140 50         if (expect_false( start_offset > len )) {
554 0           SRL_RDR_ERROR(dec->pbuf, "Start offset is beyond input string length");
555             }
556 865140           dec->buf.start= dec->buf.pos= tmp + start_offset;
557 865140           dec->buf.end= dec->buf.start + len - start_offset;
558 865140           SRL_RDR_SET_BODY_POS(dec->pbuf, dec->buf.start);
559 865140           dec->bytes_consumed = 0;
560              
561 865140           return dec;
562             }
563              
564             IV
565 10116           srl_validate_header_version_pv_len(pTHX_ char *strdata, STRLEN len)
566             {
567 10116           return srl_validate_header_version(aTHX_ (srl_reader_char_ptr) strdata, len);
568             }
569              
570             SRL_STATIC_INLINE void
571 865140           srl_read_header(pTHX_ srl_decoder_t *dec, SV *header_user_data)
572             {
573             UV header_len;
574 865140           IV proto_version_and_encoding_flags_int= srl_validate_header_version(aTHX_ dec->buf.pos, SRL_RDR_SPACE_LEFT(dec->pbuf));
575              
576 865140 100         if ( expect_false(proto_version_and_encoding_flags_int < 1) ) {
577 7 100         if (proto_version_and_encoding_flags_int == 0)
578 2           SRL_RDR_ERROR(dec->pbuf, "Bad Sereal header: It seems your document was accidentally UTF-8 encoded");
579             else
580 5           SRL_RDR_ERROR(dec->pbuf, "Bad Sereal header: Not a valid Sereal document.");
581             }
582             else {
583 865133           dec->buf.pos += 5;
584              
585 865133           dec->proto_version = (U8)(proto_version_and_encoding_flags_int & SRL_PROTOCOL_VERSION_MASK);
586 865133           dec->encoding_flags = (U8)(proto_version_and_encoding_flags_int & SRL_PROTOCOL_ENCODING_MASK);
587              
588 865133 100         if (expect_false( dec->proto_version == 1 ))
589 48773           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_PROTOCOL_V1); /* compat mode */
590 816360 50         else if (expect_false( dec->proto_version > SRL_PROTOCOL_VERSION || dec->proto_version < 1 ))
    50          
    50          
591 0           SRL_RDR_ERRORf1(dec->pbuf, "Unsupported Sereal protocol version %u", dec->proto_version);
592              
593 865133 100         if (dec->encoding_flags == SRL_PROTOCOL_ENCODING_RAW) {
594             /* no op */
595             }
596             else
597 88000 100         if ( dec->encoding_flags == SRL_PROTOCOL_ENCODING_SNAPPY
598 81518 100         || dec->encoding_flags == SRL_PROTOCOL_ENCODING_SNAPPY_INCREMENTAL)
599             {
600 58324 100         if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_REFUSE_SNAPPY) )) {
601 2           SRL_RDR_ERROR(dec->pbuf, "Sereal document is compressed with Snappy, "
602             "but this decoder is configured to refuse Snappy-compressed input.");
603             }
604 58322           dec->flags |= SRL_F_DECODER_DECOMPRESS_SNAPPY;
605             }
606             else
607 29676 100         if (dec->encoding_flags == SRL_PROTOCOL_ENCODING_ZLIB)
608             {
609 20140 50         if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_REFUSE_ZLIB) )) {
610 0           SRL_RDR_ERROR(dec->pbuf, "Sereal document is compressed with ZLIB, "
611             "but this decoder is configured to refuse ZLIB-compressed input.");
612             }
613 20140           dec->flags |= SRL_F_DECODER_DECOMPRESS_ZLIB;
614             }
615             else
616 9536 50         if (dec->encoding_flags == SRL_PROTOCOL_ENCODING_ZSTD)
617             {
618 9536 50         if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_REFUSE_ZSTD) )) {
619 0           SRL_RDR_ERROR(dec->pbuf, "Sereal document is compressed with ZSTD, "
620             "but this decoder is configured to refuse ZSTD-compressed input.");
621             }
622 9536           dec->flags |= SRL_F_DECODER_DECOMPRESS_ZSTD;
623             }
624             else
625             {
626 0           SRL_RDR_ERRORf1(dec->pbuf, "Sereal document encoded in an unknown format '%d'",
627             dec->encoding_flags >> SRL_PROTOCOL_VERSION_BITS);
628             }
629              
630             /* Must do this via a temporary as it modifes dec->buf.pos itself */
631 865131           header_len= srl_read_varint_uv_length(aTHX_ dec->pbuf, " while reading header");
632              
633 1189971 100         if (dec->proto_version > 1 && header_len) {
    100          
634             /* We have a protocol V2+ extensible header:
635             * - 8bit bitfield
636             * - if lowest bit set, we have custom-header-user-data after the bitfield
637             * => Only read header user data if an SV* was passed in to fill. */
638              
639             U8 bitfield;
640              
641 324840 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, 1, " while reading header flags");
642              
643 324840           bitfield = *(dec->buf.pos++);
644 324840 50         if (bitfield & SRL_PROTOCOL_HDR_USER_DATA && header_user_data != NULL) {
    100          
645             /* Do an actual document body deserialization for the user data: */
646 162360 50         SRL_RDR_UPDATE_BODY_POS(dec->pbuf, dec->proto_version);
647 162360           srl_read_single_value(aTHX_ dec, header_user_data, NULL);
648 162360 100         if (expect_false(SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_NEEDS_FINALIZE))) {
649 4680           srl_finalize_structure(aTHX_ dec);
650             }
651 162360           srl_clear_decoder_body_state(aTHX_ dec); /* clean up for the main body decode */
652             }
653             else {
654             /* Either off in bitfield or no user data wanted, skip to end of header */
655 162480 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, header_len, " while reading header packet");
    50          
    50          
656 162480           dec->buf.pos += header_len - 1; /* header_len includes bitfield */
657             }
658             }
659             else {
660             /* Skip header since we don't have any defined header-content in this
661             * protocol version. */
662 540291           dec->buf.pos += header_len;
663             }
664             }
665 865131           }
666              
667             SRL_STATIC_INLINE void
668 24844           srl_finalize_structure(pTHX_ srl_decoder_t *dec)
669             {
670 24844           int nobless = SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_NO_BLESS_OBJECTS);
671              
672 24844 100         if (dec->weakref_av)
673 11           av_clear(dec->weakref_av);
674 24844 100         if (dec->ref_stashes) {
675             /* The iterator could be leaked on exceptions if not for PTABLE_FLAG_AUTOCLEAN. */
676 24841           PTABLE_ITER_t *it = PTABLE_iter_new_flags(dec->ref_stashes, PTABLE_FLAG_AUTOCLEAN);
677             PTABLE_ENTRY_t *ent;
678              
679             /* We have gotten here without error, so bless all the objects.
680             * We defer to the end like this so that we only bless data structures
681             * if the entire deserialization completes. */
682 50318 100         while ( NULL != (ent = PTABLE_iter_next(it)) ) {
683 25477           HV *stash = (HV* )ent->value;
684 25477           AV *ref_bless_av = (AV *) PTABLE_fetch(dec->ref_bless_av, ent->key);
685             I32 len;
686 25477 50         if (expect_false( !stash || !ref_bless_av )) {
    50          
    50          
687 0           PTABLE_iter_free(it);
688 0           SRL_RDR_ERROR(dec->pbuf, "missing stash or ref_bless_av!");
689             }
690 51599 100         for( len= av_len(ref_bless_av) + 1 ; len > 0 ; len-- ) {
691 26122           SV* obj= av_pop(ref_bless_av); /*note that av_pop does NOT refcnt dec the sv*/
692 26122 50         if (SvREFCNT(obj)>1) {
693             /* It is possible that someone handcrafts a hash with a key collision,
694             * which could trick us into effectively blessing an object and then
695             * calling DESTROY on it. So we track the refcount of the objects
696             * popped off the ref_bless_av, and only bless if their refcount *before*
697             * we refcount dec is higher than 1. If it is 1 then we just destroy the
698             * object.
699             * */
700 26122 50         if (expect_true( obj )) {
701             #if USE_588_WORKAROUND
702             /* was blessed early, don't rebless */
703             #else
704 26122 100         if (!nobless) {
705 26121 100         if ( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_READONLY_FLAGS) && SvREADONLY(SvRV(obj))) {
    100          
706             /* the referenced scalar was readonly, temporary
707             set it rw to bless its reference */
708 1852           SvREADONLY_off(SvRV(obj));
709 1852           sv_bless(obj, stash);
710 1852           SvREADONLY_on(SvRV(obj));
711             } else {
712 26122           sv_bless(obj, stash);
713             }
714             }
715             #endif
716             } else {
717 0           PTABLE_iter_free(it);
718 0           SRL_RDR_ERROR(dec->pbuf, "object missing from ref_bless_av array?");
719             }
720             } else {
721 0           warn("serialization contains a duplicated key, ignoring");
722             }
723 26122           SvREFCNT_dec(obj);
724             }
725             }
726 24841           PTABLE_iter_free(it);
727             }
728 24844           }
729              
730              
731             /* PRIVATE UTILITY FUNCTIONS */
732              
733             SRL_STATIC_INLINE void
734 0           srl_track_thawed(srl_decoder_t *dec, const U8 *track_pos, SV *sv)
735             {
736 0 0         if (!dec->ref_thawhash)
737 0           dec->ref_thawhash = PTABLE_new();
738 0           PTABLE_store(dec->ref_thawhash, (void *)(track_pos - dec->buf.body_pos), (void *)sv);
739 0           }
740              
741              
742             SRL_STATIC_INLINE SV *
743 218167           srl_fetch_thawed(srl_decoder_t *dec, UV item)
744             {
745 218167 50         if (dec->ref_thawhash) {
746 0           SV *sv= (SV *)PTABLE_fetch(dec->ref_thawhash, (void *)item);
747 0           return sv;
748             } else {
749 218167           return NULL;
750             }
751             }
752              
753             SRL_STATIC_INLINE void
754 225333           srl_track_sv(pTHX_ srl_decoder_t *dec, const U8 *track_pos, SV *sv)
755             {
756 225333           PTABLE_store(dec->ref_seenhash, (void *)(track_pos - dec->buf.body_pos), (void *)sv);
757 225333           }
758              
759              
760             SRL_STATIC_INLINE SV *
761 314853           srl_fetch_item(pTHX_ srl_decoder_t *dec, UV item, const char * const tag_name)
762             {
763 314853           SV *sv= (SV *)PTABLE_fetch(dec->ref_seenhash, (void *)item);
764             #ifndef FOLLOW_REFERENCES_IF_NOT_STASHED
765 314853 100         if (expect_false( !sv )) {
766             /*srl_ptable_debug_dump(aTHX_ dec->ref_seenhash);*/
767 1           SRL_RDR_ERRORf2(dec->pbuf, "%s(%"UVuf") references an unknown item", tag_name, item);
768             }
769             #endif
770 314852           return sv;
771             }
772              
773             /****************************************************************************
774             * PRIVATE WORKER SUBS FOR DEPARSING *
775             ****************************************************************************/
776             SRL_STATIC_INLINE void
777 547           srl_alias_iv(pTHX_ srl_decoder_t *dec, SV **container, const U8 *track_it, IV iv)
778             {
779             SV *alias;
780 547           SV **av_array= AvARRAY(dec->alias_cache);
781 547           U32 ofs = iv + 16; /* we always cover from -16 up so we add 16 */
782              
783             assert( IS_IV_ALIAS(dec,iv) );
784              
785 547 100         if (!av_array[ofs] || av_array[ofs] == &PL_sv_undef) {
    50          
786 182           alias= newSViv(iv);
787             /* mark it as readonly so people dont try to modify it */
788 182           SvREADONLY_on(alias);
789             /* store it in the alias_cache array */
790 182           av_array[ofs]= alias;
791             } else {
792 365           alias= av_array[ofs];
793             }
794              
795 547           SvREFCNT_inc(alias);
796              
797 547 50         if (*container && *container != &PL_sv_undef)
    50          
798 547           SvREFCNT_dec(*container);
799 547           *container= alias;
800 547 100         if (track_it)
801 3           srl_track_sv(aTHX_ dec, track_it, alias);
802 547           }
803              
804              
805              
806             SRL_STATIC_INLINE void
807 625922           srl_setiv(pTHX_ srl_decoder_t *dec, SV *into, SV **container, const U8 *track_it, IV iv)
808             {
809 625922 100         if ( expect_false( container && IS_IV_ALIAS(dec,iv) )) {
    100          
    50          
    50          
    100          
810 547           srl_alias_iv(aTHX_ dec, container, track_it, iv);
811             } else {
812             /* unroll sv_setiv() for the SVt_NULL case, which we will
813             * see regularly - this wins about 35% speedup for us
814             * but involve gratuitious intimacy with the internals.
815             * */
816             #ifdef FAST_IV
817 625375 100         if ( SvTYPE(into) == SVt_NULL ) {
818             /* XXX: dont need to do this, we are null already */
819             /* SvFLAGS(into) &= ~SVTYPEMASK; */
820             assert(
821             (SVt_NULL == 0) &&
822             ((SvFLAGS(into) & (SVTYPEMASK|SVf_OOK|SVf_OK|SVf_IVisUV|SVf_UTF8)) == 0)
823             );
824 625364           SvANY(into) = (XPVIV*)((char*)&(into->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
825             /* replace this: */
826             /* SvIOK_only(into); */
827             /* with this: */
828 625364           SvFLAGS(into) |= (SVt_IV | SVf_IOK | SVp_IOK);
829 625364           SvIV_set(into, iv);
830             } else
831             #endif
832             {
833 11           sv_setiv(into, iv);
834             }
835             }
836 625922           }
837              
838             SRL_STATIC_INLINE void
839 330991           srl_read_varint_into(pTHX_ srl_decoder_t *dec, SV* into, SV **container, const U8 *track_it)
840             {
841 330991           UV uv= srl_read_varint_uv(aTHX_ dec->pbuf);
842 330991 100         if (expect_true(uv <= (UV)IV_MAX)) {
843 287743           srl_setiv(aTHX_ dec, into, container, track_it, (IV)uv);
844             } else {
845             /* grr, this is ridiculous! */
846 43248           sv_setiv(into, 0);
847 43248           SvIsUV_on(into);
848 43248           SvUV_set(into, uv);
849             }
850 330991           }
851              
852              
853             SRL_STATIC_INLINE IV
854 141226           srl_read_zigzag_iv(pTHX_ srl_decoder_t *dec)
855             {
856 141226           UV n= srl_read_varint_uv(aTHX_ dec->pbuf);
857 141226           IV i= (n >> 1) ^ (-(n & 1));
858 141226           return i;
859             }
860              
861             SRL_STATIC_INLINE void
862 141226           srl_read_zigzag_into(pTHX_ srl_decoder_t *dec, SV* into, SV **container, const U8 *track_it)
863             {
864 141226           srl_setiv(aTHX_ dec, into, container, track_it, srl_read_zigzag_iv(aTHX_ dec));
865 141226           }
866              
867              
868             SRL_STATIC_INLINE void
869 524250           srl_read_string(pTHX_ srl_decoder_t *dec, int is_utf8, SV* into)
870             {
871 524250           UV len= srl_read_varint_uv_length(aTHX_ dec->pbuf, " while reading string");
872 524250 100         if (expect_false(is_utf8 && SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_VALIDATE_UTF8))) {
    100          
    100          
873             /* checks for invalid byte sequences. */
874 9 100         if (expect_false( !is_utf8_string((U8*)dec->buf.pos, len) )) {
875 3           SRL_RDR_ERROR(dec->pbuf, "Invalid UTF8 byte sequence");
876             }
877             }
878 524247           sv_setpvn(into,(char *)dec->buf.pos,len);
879 524247 100         if (is_utf8) {
880 101856           SvUTF8_on(into);
881             } else {
882 422391           SvUTF8_off(into);
883             }
884 524247           dec->buf.pos+= len;
885 524247           }
886              
887             /* declare a union so that we are guaranteed the right alignment
888             * rules - this is required for e.g. ARM */
889             union myfloat {
890             U8 c[sizeof(long double)];
891             float f;
892             double d;
893             long double ld;
894             };
895              
896             /* XXX Most (if not all?) non-x86 platforms are strict in their
897             * floating point alignment. So maybe this logic should be the other
898             * way: default to strict, and do sloppy only if x86? */
899              
900             SRL_STATIC_INLINE void
901 10812           srl_read_float(pTHX_ srl_decoder_t *dec, SV* into)
902             {
903             union myfloat val;
904 10812 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, sizeof(float), " while reading FLOAT");
905             #if SRL_USE_ALIGNED_LOADS_AND_STORES
906             Copy(dec->buf.pos,val.c,sizeof(float),U8);
907             #else
908 10812           val.f= *((float *)dec->buf.pos);
909             #endif
910 10812           sv_setnv(into, (NV)val.f);
911 10812           dec->buf.pos+= sizeof(float);
912 10812           }
913              
914              
915             SRL_STATIC_INLINE void
916 152640           srl_read_double(pTHX_ srl_decoder_t *dec, SV* into)
917             {
918             union myfloat val;
919 152640 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, sizeof(double), " while reading DOUBLE");
920             #if SRL_USE_ALIGNED_LOADS_AND_STORES
921             Copy(dec->buf.pos,val.c,sizeof(double),U8);
922             #else
923 152640           val.d= *((double *)dec->buf.pos);
924             #endif
925 152640           sv_setnv(into, (NV)val.d);
926 152640           dec->buf.pos+= sizeof(double);
927 152640           }
928              
929              
930             SRL_STATIC_INLINE void
931 0           srl_read_long_double(pTHX_ srl_decoder_t *dec, SV* into)
932             {
933             union myfloat val;
934 0 0         SRL_RDR_ASSERT_SPACE(dec->pbuf, sizeof(long double), " while reading LONG_DOUBLE");
935             #if SRL_USE_ALIGNED_LOADS_AND_STORES
936             Copy(dec->buf.pos,val.c,sizeof(long double),U8);
937             #else
938 0           val.ld= *((long double *)dec->buf.pos);
939             #endif
940 0           sv_setnv(into, (NV)val.ld);
941 0           dec->buf.pos+= sizeof(long double);
942 0           }
943              
944              
945             SRL_STATIC_INLINE void
946 785989           srl_read_array(pTHX_ srl_decoder_t *dec, SV *into, U8 tag) {
947             UV len;
948 785989 100         if (tag) {
949 465157           SV *referent= (SV *)newAV();
950 465157           len= tag & 15;
951 465157 100         SRL_sv_set_rv_to(into, referent);
    100          
    100          
    50          
    0          
    0          
    0          
952 465157           into= referent;
953 465157 100         DEPTH_INCREMENT(dec);
954             } else {
955 320832           len= srl_read_varint_uv_count(aTHX_ dec->pbuf, " while reading ARRAY");
956 320832 50         (void)SvUPGRADE(into, SVt_PVAV);
957             }
958              
959 785988 100         if (len) {
960             SV **av_array;
961             SV **av_end;
962              
963 763066 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,len," while reading array contents, insufficient remaining tags for specified array size");
    50          
    50          
964              
965             /* make sure the array has room */
966 763066           av_extend((AV*)into, len-1);
967             /* set the size */
968 763066           AvFILLp(into)= len - 1;
969              
970 763066           av_array= AvARRAY((AV*)into);
971 763066           av_end= av_array + len;
972              
973 2622208 100         for ( ; av_array < av_end ; av_array++) {
974 1860143           *av_array = FRESH_SV();
975 1860143           srl_read_single_value(aTHX_ dec, *av_array, av_array);
976             }
977             }
978 784987 100         if (tag)
979 464155           DEPTH_DECREMENT(dec);
980 784987           }
981              
982             #ifndef HV_FETCH_LVALUE
983             # define OLDHASH
984             # define IS_LVALUE 1
985             # define KEYLENTYPE IV
986             #else
987             # define KEYLENTYPE STRLEN
988             #endif
989              
990             #ifndef HvRITER_set
991             # define HvRITER_set(sv,v) HvRITER(sv) = v
992             #endif
993              
994             SRL_STATIC_INLINE void
995 227557           srl_read_hash(pTHX_ srl_decoder_t *dec, SV* into, U8 tag) {
996             UV num_keys;
997 227557 100         if (tag) {
998 131909           SV *referent= (SV *)newHV();
999 131909           num_keys= tag & 15;
1000 131909 100         SRL_sv_set_rv_to(into, referent);
    50          
    50          
    100          
    50          
    0          
    0          
1001 131909           into= referent;
1002 131909 50         DEPTH_INCREMENT(dec);
1003             } else {
1004 95648           num_keys= srl_read_varint_uv_count(aTHX_ dec->pbuf, " while reading HASH");
1005 95648 50         (void)SvUPGRADE(into, SVt_PVHV);
1006             }
1007             /* in some versions of Perl HvRITER() is not properly set on an upgrade SV
1008             * so we explicitly set it ourselves */
1009             #ifdef FIXUP_RITER
1010             HvRITER_set(into,-1);
1011             #endif
1012              
1013             /* Limit the maximum number of hash keys that we accept to whetever was configured */
1014 227557 100         if (expect_false( dec->max_num_hash_entries != 0 && num_keys > dec->max_num_hash_entries )) {
    100          
    100          
1015 4           SRL_RDR_ERRORf2(dec->pbuf, "Got input hash with %u entries, but the configured maximum is just %u",
1016             (int)num_keys, (int)dec->max_num_hash_entries);
1017             }
1018              
1019 227553 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,num_keys*2," while reading hash contents, insufficient remaining tags for number of keys specified");
    50          
    50          
1020              
1021 227553           HvSHAREKEYS_on(into); /* apparently required on older perls */
1022              
1023 227553           hv_ksplit((HV *)into, num_keys); /* make sure we have enough room */
1024             /* NOTE: contents of hash are stored VALUE/KEY, reverse from normal perl
1025             * storage, this is because it simplifies the hash storage logic somewhat */
1026 872476 100         for (; num_keys > 0 ; num_keys--) {
1027             const U8 *from;
1028             U8 tag;
1029             SV **fetched_sv;
1030             #ifndef OLDHASH
1031 644924           U32 flags= 0;
1032             #endif
1033             KEYLENTYPE key_len;
1034              
1035 644924 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,1," while reading key tag byte for HASH");
1036 644924           tag= (*dec->buf.pos++)&127;
1037 644924 100         if (IS_SRL_HDR_SHORT_BINARY(tag)) {
1038 618105           key_len= (KEYLENTYPE)SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag);
1039 618105 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,key_len," while reading string/SHORT_BINARY key");
    50          
    50          
1040 618105           from= dec->buf.pos;
1041 618105           dec->buf.pos += key_len;
1042 26819 100         } else if (tag == SRL_HDR_BINARY) {
1043 12609           key_len= (KEYLENTYPE)srl_read_varint_uv_length(aTHX_ dec->pbuf, " while reading string/BINARY key");
1044 12609 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,key_len," while reading binary key");
    50          
    50          
1045 12609           from= dec->buf.pos;
1046 12609           dec->buf.pos += key_len;
1047 14210 100         } else if (tag == SRL_HDR_STR_UTF8) {
1048 3           key_len= (KEYLENTYPE)srl_read_varint_uv_length(aTHX_ dec->pbuf, " while reading UTF8 key");
1049 3 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,key_len," while reading string key");
    50          
    50          
1050 3           from= dec->buf.pos;
1051 3           dec->buf.pos += key_len;
1052             #ifdef OLDHASH
1053             key_len= -key_len;
1054             #else
1055 3           flags= HVhek_UTF8;
1056             #endif
1057 14207 50         } else if (tag == SRL_HDR_COPY) {
1058 14207           UV ofs= srl_read_varint_uv_offset(aTHX_ dec->pbuf, " while reading COPY tag");
1059 14207           from= dec->buf.body_pos + ofs;
1060 14207           tag= *from++;
1061             /* note we do NOT validate these items, as we have alread read them
1062             * and if they were a problem we would not be here to process them! */
1063 14207 50         if (IS_SRL_HDR_SHORT_BINARY(tag)) {
1064 14207           key_len= (KEYLENTYPE)SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag);
1065             }
1066             else
1067 0 0         if (tag == SRL_HDR_BINARY) {
1068 0           key_len = (KEYLENTYPE)S_read_varint_uv_length_char_ptr(
1069 0           aTHX_ &from, dec->buf.end,
1070             " while reading (byte) string length (via COPY)"
1071             );
1072             }
1073             else
1074 0 0         if (tag == SRL_HDR_STR_UTF8) {
1075 0           key_len = (KEYLENTYPE)S_read_varint_uv_length_char_ptr(
1076 0           aTHX_ &from, dec->buf.end,
1077             " while reading UTF8-encoded string length (via COPY)"
1078             );
1079             #ifdef OLDHASH
1080             key_len= -key_len;
1081             #else
1082 0           flags= HVhek_UTF8;
1083             #endif
1084             }
1085             else {
1086 14207           SRL_RDR_ERROR_BAD_COPY(dec->pbuf, SRL_HDR_HASH);
1087             }
1088             } else {
1089 0           SRL_RDR_ERROR_UNEXPECTED(dec->pbuf, tag, "a stringish type");
1090             }
1091 644924 100         if (SvREADONLY(into)) {
1092 1           SvREADONLY_off(into);
1093             }
1094             #ifdef OLDHASH
1095             fetched_sv= hv_fetch((HV *)into, (char *)from, key_len, IS_LVALUE);
1096             #else
1097 644924           fetched_sv= (SV **) hv_common((HV *)into, NULL, (char *)from, key_len, flags, HV_FETCH_LVALUE|HV_FETCH_JUST_SV, NULL, 0);
1098             #endif
1099 644924 50         if (expect_false( !fetched_sv )) {
1100 0           SRL_RDR_ERROR_PANIC(dec->pbuf, "failed to hv_store");
1101             }
1102             else
1103 644924 50         if ( expect_false( SvTYPE(*fetched_sv) != SVt_NULL ) ) {
1104             /* sv_dump(*fetched_sv); */
1105 0           SRL_RDR_ERRORf2(dec->pbuf, "duplicate key '%.*s' in hash", (int) key_len, (char *)from);
1106             }
1107 644924           srl_read_single_value(aTHX_ dec, *fetched_sv, fetched_sv );
1108             }
1109 227552 100         if (tag)
1110 131908           DEPTH_DECREMENT(dec);
1111 227552           }
1112              
1113              
1114             SRL_STATIC_INLINE void
1115 955869           srl_read_refn(pTHX_ srl_decoder_t *dec, SV* into)
1116             {
1117             SV *referent;
1118             U8 tag;
1119 955869 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, 1, " while reading REFN referent");
1120 955869           tag= *(dec->buf.pos); /* Look ahead for special vars. */
1121 955869 100         if (tag == SRL_HDR_TRUE) {
1122 1           dec->buf.pos++;
1123 1           referent= &PL_sv_yes;
1124             }
1125 955868 100         else if (tag == SRL_HDR_FALSE) {
1126 1           dec->buf.pos++;
1127 1           referent= &PL_sv_no;
1128             }
1129             /*
1130             * Note the below is guarded by an option as we have use SRL_HDR_UNDEF
1131             * also to represent "any SV which is undef", and using to represent
1132             * true PL_sv_undef will break things.
1133             *
1134             * We need a new, different tag for true perl undef.
1135             *
1136             */
1137             else
1138 955867 100         if (
1139             ( tag == SRL_HDR_CANONICAL_UNDEF )
1140 932016 50         ||
1141 0 0         ( SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_USE_UNDEF) && tag == SRL_HDR_UNDEF )
1142             ) {
1143 23851           dec->buf.pos++;
1144 23851           referent= &PL_sv_undef;
1145             }
1146             else {
1147 932016           referent= FRESH_SV();
1148 932016           SvTEMP_off(referent);
1149 932016           tag = 0;
1150             }
1151 955869 100         SRL_sv_set_rv_to(into, referent);
    100          
    100          
    100          
    50          
    0          
    0          
1152 955869 100         if (!tag) {
1153 932016 50         DEPTH_INCREMENT(dec);
1154 932016           srl_read_single_value(aTHX_ dec, referent, NULL);
1155 932012           DEPTH_DECREMENT(dec);
1156             }
1157 955865           }
1158              
1159             SRL_STATIC_INLINE SV *
1160             srl_follow_refp_alias_reference(pTHX_ srl_decoder_t *dec, UV offset)
1161             {
1162             SV* into = sv_2mortal(FRESH_SV());
1163             srl_reader_char_ptr orig_pos = dec->buf.pos;
1164             srl_reader_char_ptr new_pos = dec->buf.body_pos + offset;
1165              
1166             if (new_pos >= orig_pos) {
1167             SRL_RDR_ERROR(dec->pbuf, "Corrupted packed. Reference offset points forward!");
1168             }
1169              
1170             dec->buf.pos = new_pos;
1171             srl_read_single_value(aTHX_ dec, into, NULL);
1172             dec->buf.pos = orig_pos;
1173             return into;
1174             }
1175              
1176             SRL_STATIC_INLINE AV *
1177             srl_follow_objectv_reference(pTHX_ srl_decoder_t *dec, UV offset)
1178             {
1179             AV *av= NULL;
1180             srl_reader_char_ptr orig_pos = dec->buf.pos;
1181             srl_reader_char_ptr new_pos = dec->buf.body_pos + offset;
1182              
1183             if (new_pos >= orig_pos) {
1184             SRL_RDR_ERROR(dec->pbuf, "Corrupted packed. Reference offset points forward!");
1185             }
1186              
1187             SRL_ASSERT_REF_PTR_TABLES(dec); /* init dec->ref_stashes and dec->ref_bless_av */
1188              
1189             dec->buf.pos = new_pos;
1190             /* call srl_read_object() with read_class_name_only=1 */
1191             /* into and obj_tag are not used in this case */
1192             srl_read_object(aTHX_ dec, NULL, 0, 1);
1193             av= (AV *)PTABLE_fetch(dec->ref_bless_av, (void *)offset);
1194             dec->buf.pos = orig_pos;
1195             return av;
1196             }
1197              
1198             SRL_STATIC_INLINE void
1199 218167           srl_read_refp(pTHX_ srl_decoder_t *dec, SV* into)
1200             {
1201             /* something we did before */
1202 218167           UV item= srl_read_varint_uv_offset(aTHX_ dec->pbuf, " while reading REFP tag");
1203 218167           SV *thawed= srl_fetch_thawed(dec, item);
1204             SV *referent;
1205 218167 50         if (thawed) {
1206 0           sv_setsv(into, thawed);
1207 0           return;
1208             }
1209 218167           referent= srl_fetch_item(aTHX_ dec, item, "REFP");
1210              
1211             #ifdef FOLLOW_REFERENCES_IF_NOT_STASHED
1212             if (referent == NULL)
1213             referent = srl_follow_refp_alias_reference(aTHX_ dec, item);
1214             #endif
1215              
1216 218167           (void)SvREFCNT_inc(referent);
1217              
1218 218167 50         SRL_sv_set_rv_to(into, referent);
    50          
    0          
    0          
    0          
    0          
    0          
1219              
1220             #if USE_588_WORKAROUND
1221             /* See 'define USE_588_WORKAROUND' above for a discussion of what this does. */
1222             if (SvOBJECT(referent)) {
1223             HV *stash = SvSTASH(referent);
1224             if (Gv_AMG(stash))
1225             SvAMAGIC_on(into);
1226             }
1227             #endif
1228             }
1229              
1230              
1231             SRL_STATIC_INLINE void
1232 13           srl_read_weaken(pTHX_ srl_decoder_t *dec, SV* into)
1233             {
1234             SV* referent;
1235             /* TODO This really just wants a subset of the states that srl_read_single_value covers, right?
1236             * Optimization opportunity? Or robustness against invalid packets issue? */
1237 13           srl_read_single_value(aTHX_ dec, into, NULL);
1238 13 50         if (expect_false( !SvROK(into) ))
1239 0           SRL_RDR_ERROR(dec->pbuf, "WEAKEN op");
1240 13           referent= SvRV(into);
1241             /* we have to be careful to not allow the referent's refcount
1242             * to go to zero in the process of us weakening the ref.
1243             * For instance this may be aliased or reused later by a non-weakref
1244             * which will "fix" the refcount, however we need to be able to deserialize
1245             * in the opposite order, so if the referent's refcount is 1
1246             * we increment it and stuff it in the weakref_av before we call
1247             * sv_rvweaken(), right before we exit we clear any items from
1248             * that array, which does the REFCNT_dec for us, and everything
1249             * works out ok. */
1250 13 100         if (expect_true( SvREFCNT(referent)==1 )) {
1251 3 50         if (expect_false( !dec->weakref_av ))
1252 3           dec->weakref_av= newAV();
1253 3           av_push(dec->weakref_av, SvREFCNT_inc(referent));
1254 3           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_NEEDS_FINALIZE);
1255             }
1256              
1257             /* If read-only reference, set to rw only to weaken it, otherwise "Modification of a read-only value attempted". */
1258 13 100         if ( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_READONLY_FLAGS) && SvREADONLY(into)) {
    100          
1259 1           SvREADONLY_off(into);
1260 1           sv_rvweaken(into);
1261 1           SvREADONLY_on(into);
1262             } else {
1263 12           sv_rvweaken(into);
1264             }
1265 13           }
1266              
1267             SRL_STATIC_INLINE void
1268 645           srl_read_objectv(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag)
1269             {
1270 645           AV *av= NULL;
1271             STRLEN ofs;
1272              
1273 645 50         if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_REFUSE_OBJECTS) ))
1274 0           SRL_RDR_ERROR_REFUSE_OBJECT(dec->pbuf);
1275              
1276 645           ofs= srl_read_varint_uv_offset(aTHX_ dec->pbuf, " while reading OBJECTV(_FREEZE) classname");
1277              
1278 645 50         if (expect_false( !dec->ref_bless_av )) {
1279             #ifdef FOLLOW_REFERENCES_IF_NOT_STASHED
1280             SRL_ASSERT_REF_PTR_TABLES(dec); /* init dec->ref_stashes and dec->ref_bless_av */
1281             #else
1282 0           SRL_RDR_ERROR(dec->pbuf, "Corrupted packet. OBJECTV(_FREEZE) used without "
1283             "preceding OBJECT(_FREEZE) to define classname");
1284             #endif
1285             }
1286              
1287 645           av= (AV *)PTABLE_fetch(dec->ref_bless_av, (void *)ofs);
1288 645 50         if (expect_false( NULL == av )) {
1289             #ifdef FOLLOW_REFERENCES_IF_NOT_STASHED
1290             av = srl_follow_objectv_reference(aTHX_ dec, (UV) ofs);
1291             if (expect_false( NULL == av ))
1292             #endif
1293 0           SRL_RDR_ERRORf1(dec->pbuf, "Corrupted packet. OBJECTV(_FREEZE) references unknown classname offset: %"UVuf, (UV)ofs);
1294             }
1295              
1296             /* checking tag: SRL_HDR_OBJECTV_FREEZE or SRL_HDR_OBJECTV? */
1297 645 50         if (expect_false( obj_tag == SRL_HDR_OBJECTV_FREEZE )) {
1298 0           HV *class_stash= (HV *) PTABLE_fetch(dec->ref_stashes, (void *)ofs);
1299 0 0         if (expect_false( class_stash == NULL ))
1300 0           SRL_RDR_ERROR(dec->pbuf, "Corrupted packet. OBJECTV(_FREEZE) used without "
1301             "preceding OBJECT(_FREEZE) to define classname");
1302 0           srl_read_frozen_object(aTHX_ dec, class_stash, into);
1303             } else {
1304             /* SRL_HDR_OBJECTV, not SRL_HDR_OBJECTV_FREEZE */
1305             /* now deparse the thing we are going to bless */
1306 645           srl_read_single_value(aTHX_ dec, into, NULL);
1307              
1308             /* and also stuff it into the av - we dont have to do any more book-keeping */
1309 645           av_push(av, SvREFCNT_inc(into));
1310              
1311             #if USE_588_WORKAROUND
1312             {
1313             /* See 'define USE_588_WORKAROUND' above for a discussion of what this does. */
1314             HV *class_stash= PTABLE_fetch(dec->ref_stashes, (void *)ofs);
1315             if (expect_false( class_stash == NULL ))
1316             SRL_RDR_ERROR(dec->pbuf, "Corrupted packet. OBJECTV(_FREEZE) used without "
1317             "preceding OBJECT(_FREEZE) to define classname");
1318             if (!SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_NO_BLESS_OBJECTS))
1319             sv_bless(into, class_stash);
1320             }
1321             #endif
1322             }
1323 645           }
1324              
1325             SRL_STATIC_INLINE void
1326 25481           srl_read_object(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag, int read_class_name_only)
1327             {
1328 25481           HV *class_stash= NULL;
1329 25481           AV *av= NULL;
1330 25481           STRLEN storepos= 0;
1331 25481           UV ofs= 0;
1332 25481           I32 flags= GV_ADD;
1333             U8 tag;
1334 25481           U32 key_len = 0;
1335 25481           const U8 *from = NULL;
1336              
1337 25481 100         if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_REFUSE_OBJECTS) ))
1338 2           SRL_RDR_ERROR_REFUSE_OBJECT(dec->pbuf);
1339              
1340             /* Now find the class name - first check if this is a copy op
1341             * this is bit tricky, as we could have a copy of a raw string.
1342             * We could also have a copy of a previously mentioned class
1343             * name. We have to handle both, which leads to some non-linear
1344             * code flow in the below code. */
1345 25479 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,1," while reading classname tag");
1346              
1347             /* Now read the class name and cache it */
1348 25479           storepos= SRL_RDR_BODY_POS_OFS(dec->pbuf);
1349 25479           tag= *dec->buf.pos++;
1350              
1351 25479 100         if (IS_SRL_HDR_SHORT_BINARY(tag)) {
1352 25477           key_len= SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag);
1353 25477           from= dec->buf.pos;
1354 25477 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,key_len," while reading short binary");
1355 25477           dec->buf.pos += key_len;
1356             }
1357             else
1358 2 50         if (tag == SRL_HDR_STR_UTF8) {
1359 0           key_len= srl_read_varint_uv_length(aTHX_ dec->pbuf, " while reading UTF8 class name");
1360 0           flags = flags | SVf_UTF8;
1361 0           from= dec->buf.pos;
1362 0 0         SRL_RDR_ASSERT_SPACE(dec->pbuf,key_len," while reading utf8 string");
1363 0           dec->buf.pos += key_len;
1364             }
1365             else
1366 2 100         if (tag == SRL_HDR_BINARY) {
1367 1           key_len= srl_read_varint_uv_length(aTHX_ dec->pbuf, " while reading string/BINARY class name");
1368 1           from= dec->buf.pos;
1369 1 50         SRL_RDR_ASSERT_SPACE(dec->pbuf,key_len," while reading binary");
1370 1           dec->buf.pos += key_len;
1371             }
1372             else
1373 1 50         if (tag == SRL_HDR_COPY) {
1374 1           ofs= srl_read_varint_uv_offset(aTHX_ dec->pbuf, " while reading COPY class name");
1375 1           storepos= ofs;
1376             /* if this string was seen before as part of a classname then we expect
1377             * a stash available below. However it might have been serialized as a key
1378             * or something like that, which would mean we dont have an entry in ref_stashes
1379             * anymore. So first we check if we have a stash. If we do, then we can avoid
1380             * some work. */
1381 1 50         if (expect_true( dec->ref_stashes != NULL )) {
1382 0           class_stash= (HV *) PTABLE_fetch(dec->ref_stashes, (void *)ofs);
1383             }
1384             /* Check if we actually got a class_stash back. If we didn't then we need
1385             * to deserialize the class name */
1386 1 50         if (!class_stash) {
1387 1           from= dec->buf.body_pos + ofs;
1388 1           tag= *from++;
1389             /* Note we do NOT validate these items, as we have already read them
1390             * and if they were a problem we would not be here to process them! */
1391 1 50         if (IS_SRL_HDR_SHORT_BINARY(tag)) {
1392 0           key_len= SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag);
1393             }
1394             else
1395 1 50         if (tag == SRL_HDR_BINARY) {
1396 0           key_len = (KEYLENTYPE)S_read_varint_uv_length_char_ptr(
1397 0           aTHX_ &from, dec->buf.end,
1398             " while reading (byte) length for class name (via COPY)"
1399             );
1400             }
1401             else
1402 1 50         if (tag == SRL_HDR_STR_UTF8) {
1403 0           key_len = (KEYLENTYPE)S_read_varint_uv_length_char_ptr(
1404 0           aTHX_ &from, dec->buf.end,
1405             " while reading UTF8 string length for class name (via COPY)"
1406             );
1407 0           flags = flags | SVf_UTF8;
1408 0 0         if (!is_utf8_string(from, key_len)) {
1409 0           SRL_RDR_ERROR_PANIC(dec->pbuf, "utf8 flagged classname is not actually utf8");
1410             }
1411             }
1412             else {
1413 1           SRL_RDR_ERROR_BAD_COPY(dec->pbuf, SRL_HDR_OBJECT);
1414             }
1415             }
1416             } else {
1417 0           SRL_RDR_ERROR_UNEXPECTED(dec->pbuf, tag, "a class name");
1418             }
1419              
1420             /* At this point we may or may not have a class stash. If they used a Copy there
1421             * is a decent chance we do. */
1422 25478 100         SRL_ASSERT_REF_PTR_TABLES(dec);
1423 25478 50         if (!class_stash) {
1424             /* no class stash - so we need to look it up and then store it away for future use */
1425 25478           class_stash= gv_stashpvn((char *)from, key_len, flags);
1426 25478           PTABLE_store(dec->ref_stashes, (void *)storepos, (void *)class_stash);
1427             /* Since this is the first time we have seen this stash then it is the first time
1428             * that we have stored an item in the ref_bless_av hash as well. So create a new one
1429             * and store it away. */
1430 25478           av= newAV();
1431 25478           sv_2mortal((SV*)av);
1432 25478           PTABLE_store(dec->ref_bless_av, (void *)storepos, (void *)av);
1433             } else {
1434             /* we have a class stash so we should have a ref_bless_av as well. */
1435 0           av= (AV *)PTABLE_fetch(dec->ref_bless_av, (void *)storepos);
1436 0 0         if ( !av )
1437 0           SRL_RDR_ERRORf1(dec->pbuf, "Panic, no ref_bless_av for %"UVuf, (UV)storepos);
1438             }
1439              
1440             #ifdef FOLLOW_REFERENCES_IF_NOT_STASHED
1441             /* at this point we have class name read and have coressponding records in
1442             * dec->dec->ref_stashes and dec->ref_bless_av. So, we can simply fetch
1443             * from hashes outside this function. The code */
1444             if (read_class_name_only) return;
1445             #else
1446             assert(into != NULL);
1447             assert(obj_tag != 0);
1448             #endif
1449              
1450 25478 100         if (expect_false( obj_tag == SRL_HDR_OBJECT_FREEZE )) {
1451 1           srl_read_frozen_object(aTHX_ dec, class_stash, into);
1452             } else {
1453             /* We now have a stash so we /could/ bless... except that
1454             * we don't actually want to do so right now. We want to defer blessing
1455             * until the full packet has been read. Yes it is more overhead, but
1456             * we really dont want to trigger DESTROY methods from a partial
1457             * deparse. So we insert the item into an array to be blessed later. */
1458 25477           SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_NEEDS_FINALIZE);
1459 25477           av_push(av, SvREFCNT_inc(into));
1460              
1461             /* now deparse the thing we are going to bless */
1462 25477           srl_read_single_value(aTHX_ dec, into, NULL);
1463              
1464             #if USE_588_WORKAROUND
1465             /* See 'define USE_588_WORKAROUND' above for a discussion of what this does. */
1466             if (!SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_NO_BLESS_OBJECTS))
1467             sv_bless(into, class_stash);
1468             #endif
1469              
1470             }
1471 25478           }
1472              
1473             /* Invoke a THAW callback on the given class. Pass in the next item in the
1474             * decoder stream. This is implementing the FREEZE/THAW part of
1475             * SRL_HDR_OBJECT_FREEZE and SRL_HDR_OBJECTV_FREEZE. */
1476              
1477             SRL_STATIC_INLINE void
1478 1           srl_read_frozen_object(pTHX_ srl_decoder_t *dec, HV *class_stash, SV *into)
1479             {
1480 1           GV *method = gv_fetchmethod_autoload(class_stash, "THAW", 0);
1481 1 50         char *classname = HvNAME(class_stash);
    50          
    50          
    0          
    50          
    50          
1482             SV* referent;
1483             SV *replacement;
1484              
1485             /* At this point in the input stream we should have REFN WHATEVER. The WHATEVER
1486             * may be referenced from multiple RV's in the data structure, which means that
1487             * srl_read_single_value() will cache the *unthawed* representation when we finally
1488             * process it. So we need to do some special bookkeeping here and then overwrite
1489             * that representation in the refs hash.
1490             */
1491              
1492 1           const unsigned char *fixup_pos= dec->buf.pos + 1; /* get the tag for the WHATEVER */
1493              
1494 1 50         if (expect_false( method == NULL ))
1495 0 0         SRL_RDR_ERRORf1(dec->pbuf, "No THAW method defined for class '%s'", HvNAME(class_stash));
    0          
    0          
    0          
    0          
    0          
1496              
1497 1           srl_read_single_value(aTHX_ dec, into, NULL);
1498              
1499             /* Assert that we got a top level array ref as the spec requires.
1500             * Not throwing an exception here violates expectations down the line and
1501             * can lead to segfaults. */
1502 1 50         if (expect_false( !SvROK(into) || SvTYPE(SvRV(into)) != SVt_PVAV ))
    50          
    50          
1503 0           SRL_RDR_ERROR(dec->pbuf, "Corrupted packet. OBJECT(V)_FREEZE used without "
1504             "being followed by an array reference");
1505              
1506             {
1507             int count;
1508 1           AV *arg_av= (AV*)SvRV(into);
1509 1           int arg_av_len = av_len(arg_av)+1;
1510 1           dSP;
1511              
1512 1           ENTER;
1513 1           SAVETMPS;
1514 1 50         PUSHMARK(SP);
1515              
1516 1 50         EXTEND(SP, 3);
1517             /* TODO Consider more caching for some of this */
1518 1           PUSHs(sv_2mortal(newSVpvn(classname, strlen(classname))));
1519             /* FIXME do not recreate the following SV. That's dumb and wasteful! - so long as it doesnt get modified! */
1520 1           PUSHs(sv_2mortal(newSVpvs("Sereal")));
1521             /* Push the args into the stack */
1522 2 100         for (count=0 ; count < arg_av_len; count++) {
1523 1           PUSHs((SV*)*av_fetch(arg_av, count, 0));
1524             }
1525              
1526 1           PUTBACK;
1527 1           count = call_sv((SV *)GvCV(method), G_SCALAR);
1528             /* TODO explore method lookup caching */
1529 1           SPAGAIN;
1530              
1531 1 50         if (expect_true( count == 1 )) {
1532 1           replacement = POPs;
1533 1           SvREFCNT_inc(replacement);
1534             } else {
1535 0           replacement = &PL_sv_undef;
1536             }
1537             /* If count is not 1, then it's 0. Then into is already undef. */
1538              
1539 1           PUTBACK;
1540 1 50         FREETMPS;
1541 1           LEAVE;
1542             }
1543              
1544             /* At this point "into" is an SvRV pointing at the *unthawed* representation.
1545             * This means we need to a) remove the old unthawed item and dispose of it
1546             * and b) make "into" point at the replacement, and c) if necessary store the
1547             * replacement in the sv tracking hash so that future references to this item
1548             * point at the *thawed* version. */
1549 1 50         if (SvROK(replacement)) {
1550 1           SV *tmpsv= replacement;
1551 1           replacement= SvRV(tmpsv);
1552 1           SvREFCNT_inc(replacement);
1553 1           SvREFCNT_dec(tmpsv);
1554 1           referent= SvRV(into);
1555 1           SvRV_set(into, replacement);
1556 1           SvREFCNT_dec(referent);
1557 1 50         if (*fixup_pos & SRL_HDR_TRACK_FLAG)
1558 1           srl_track_sv(aTHX_ dec, fixup_pos, replacement);
1559 0 0         } else if (*fixup_pos & SRL_HDR_TRACK_FLAG) {
1560 0           srl_track_thawed(dec, fixup_pos, replacement);
1561 0           sv_setsv(into, replacement);
1562             }
1563 1           }
1564              
1565              
1566             SRL_STATIC_INLINE void
1567             srl_read_reserved(pTHX_ srl_decoder_t *dec, U8 tag, SV* into)
1568             {
1569             const UV len = srl_read_varint_uv_length(aTHX_ dec->pbuf, " while reading reserved");
1570             (void)tag; /* unused as of now */
1571              
1572             dec->buf.pos += len; /* discard */
1573             sv_setsv(into, &PL_sv_undef);
1574             }
1575              
1576              
1577             SRL_STATIC_INLINE void
1578 17184           srl_read_regexp(pTHX_ srl_decoder_t *dec, SV* into)
1579             {
1580 17184           SV *sv_pat= FRESH_SV();
1581 17184           srl_read_single_value(aTHX_ dec, sv_pat, NULL);
1582 17184 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, 1, " while reading regexp modifer tag");
1583             /* For now we will serialize the flags as ascii strings. Maybe we should use
1584             * something else but this is easy to debug and understand - since the modifiers
1585             * are tagged it doesn't matter much, we can add other tags later */
1586 17184 50         if ( expect_true( IS_SRL_HDR_SHORT_BINARY(*dec->buf.pos) ) ) {
1587 17184           U8 mod_len= SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(*dec->buf.pos++);
1588 17184           U32 flags= 0;
1589 17184 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, mod_len, " while reading regexp modifiers");
1590 22917 100         while (mod_len > 0) {
1591 5733           mod_len--;
1592 5733           switch (*dec->buf.pos++) {
1593             case 'm':
1594 0           flags= flags | PMf_MULTILINE;
1595 0           break;
1596             case 's':
1597 0           flags= flags | PMf_SINGLELINE;
1598 0           break;
1599             case 'i':
1600 5730           flags= flags | PMf_FOLD;
1601 5730           break;
1602             case 'x':
1603 3           flags= flags | PMf_EXTENDED;
1604 3           break;
1605             #ifdef REGEXP_HAS_P_MODIFIER
1606             case 'p':
1607 0           flags = flags | PMf_KEEPCOPY;
1608 0           break;
1609             #endif
1610             default:
1611 0           SRL_RDR_ERROR(dec->pbuf, "bad modifier");
1612             break;
1613             }
1614             }
1615             #ifdef MODERN_REGEXP
1616             {
1617             /* This is ugly. We have to swap out the insides of our SV
1618             * with the one we get back from CALLREGCOMP, as there is no
1619             * way to get it to fill our SV.
1620             *
1621             * As far as I understand this works because of how the SV
1622             * is laid out. Needs to be verified with someone who knows
1623             * better.
1624             */
1625              
1626             /* compile the regex */
1627 17184           SV *referent= (SV*)CALLREGCOMP(sv_pat, flags);
1628             SV tmp;
1629              
1630             /* make sure the SV came from us (it should) and
1631             * is bodyless */
1632             assert( SvTYPE(into) == SVt_NULL );
1633              
1634             #define SWAP_DEBUG 0
1635             if (SWAP_DEBUG) { warn("before swap:"); sv_dump(into); sv_dump(referent); }
1636              
1637             /* Swap the contents of the two heads. */
1638 17184           Copy(into, &tmp, 1, SV);
1639 17184           Copy((SV*)referent, into, 1, SV);
1640 17184           Copy(&tmp, (SV*)referent, 1, SV);
1641 17184           SvREFCNT(referent)= SvREFCNT(into);
1642 17184           SvREFCNT(into)= SvREFCNT(&tmp);
1643              
1644             if (SWAP_DEBUG) { warn("after swap:"); sv_dump(into); sv_dump(referent); }
1645              
1646 17184           SvREFCNT_dec(sv_pat); /* I think we need this or we leak */
1647             /* and now throw away the head we got from the regexp engine. */
1648 17184           SvREFCNT_dec(referent);
1649             }
1650             #elif defined( TRANSITION_REGEXP )
1651             {
1652             REGEXP *referent = CALLREGCOMP(aTHX_ sv_pat, flags);
1653             SvREFCNT_dec(sv_pat);
1654             sv_magic( into, (SV*)referent, PERL_MAGIC_qr, 0, 0);
1655             SvFLAGS( into ) |= SVs_SMG;
1656             }
1657             #else
1658             {
1659             PMOP pm; /* grr */
1660             STRLEN pat_len;
1661             REGEXP *re;
1662             char *pat= SvPV(sv_pat, pat_len);
1663              
1664             Zero(&pm,1,PMOP);
1665             pm.op_pmdynflags= SvUTF8(sv_pat) ? PMdf_CMP_UTF8 : 0;
1666             pm.op_pmflags= flags;
1667              
1668             re= CALLREGCOMP(aTHX_ pat, pat + pat_len, &pm);
1669             SvREFCNT_dec(sv_pat);
1670             sv_magic( into, (SV*)re, PERL_MAGIC_qr, 0, 0);
1671             SvFLAGS( into ) |= SVs_SMG;
1672             }
1673             #endif
1674             }
1675             else {
1676 0           SRL_RDR_ERROR(dec->pbuf, "Expecting SRL_HDR_SHORT_BINARY for modifiers of regexp");
1677             }
1678 17184           }
1679              
1680             SRL_STATIC_INLINE SV *
1681 0           srl_read_extend(pTHX_ srl_decoder_t *dec, SV* into)
1682             {
1683             /* FIXME unimplemented!!! */
1684 0           SRL_RDR_ERROR_UNIMPLEMENTED(dec->pbuf, SRL_HDR_EXTEND,"EXTEND");
1685             return into;
1686             }
1687              
1688             SRL_STATIC_INLINE void
1689 19800           srl_read_copy(pTHX_ srl_decoder_t *dec, SV* into)
1690             {
1691 19800           UV item= srl_read_varint_uv_offset(aTHX_ dec->pbuf, " while reading COPY tag");
1692 19800 50         if (expect_false( dec->save_pos )) {
1693 0           SRL_RDR_ERRORf1(dec->pbuf, "COPY(%d) called during parse", (int)item);
1694             }
1695 19800 50         if (expect_false( (IV)item > dec->buf.end - dec->buf.start )) {
1696 0           SRL_RDR_ERRORf1(dec->pbuf, "COPY(%d) points out of packet", (int)item);
1697             }
1698 19800           dec->save_pos= dec->buf.pos;
1699 19800           dec->buf.pos= dec->buf.body_pos + item;
1700 19800           srl_read_single_value(aTHX_ dec, into, NULL);
1701 19800           dec->buf.pos= dec->save_pos;
1702 19800           dec->save_pos= 0;
1703 19800           }
1704              
1705              
1706              
1707             /****************************************************************************
1708             * MAIN DISPATCH SUB - ALL ROADS LEAD HERE *
1709             ****************************************************************************/
1710              
1711             void
1712 0           srl_decode_single_value(pTHX_ srl_decoder_t *dec, SV* into, SV** container)
1713             {
1714 0           srl_read_single_value(aTHX_ dec, into, container);
1715 0           }
1716              
1717             SRL_STATIC_INLINE void
1718 4365214           srl_read_single_value(pTHX_ srl_decoder_t *dec, SV* into, SV** container)
1719             {
1720             STRLEN len;
1721             U8 tag;
1722 4365214           int is_ref = 0;
1723 4365214           const U8 *track_it = NULL;
1724              
1725             read_again:
1726 4365217 50         if (expect_false( SRL_RDR_DONE(dec->pbuf) ))
1727 0           SRL_RDR_ERROR(dec->pbuf, "unexpected end of input stream while expecting a single value");
1728              
1729 4365217           tag= *dec->buf.pos++;
1730              
1731             read_tag:
1732 4590547           switch (tag) {
1733             CASE_SRL_HDR_POS:
1734 175209           srl_setiv(aTHX_ dec, into, container, track_it, (IV)tag);
1735 175209           break;
1736             CASE_SRL_HDR_NEG:
1737 21744           srl_setiv(aTHX_ dec, into, container, track_it, (IV)(tag - 32));
1738 21744           break;
1739             CASE_SRL_HDR_SHORT_BINARY:
1740 608933           len= (STRLEN)SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag);
1741 608933 50         SRL_RDR_ASSERT_SPACE(dec->pbuf, len, " while reading ascii string");
    50          
    50          
1742 608933           sv_setpvn(into,(char*)dec->buf.pos,len);
1743 608933           dec->buf.pos += len;
1744 608933           break;
1745 131909           CASE_SRL_HDR_HASHREF: srl_read_hash(aTHX_ dec, into, tag); is_ref = 1; break;
1746 465157           CASE_SRL_HDR_ARRAYREF: srl_read_array(aTHX_ dec, into, tag); is_ref = 1; break;
1747 330991           case SRL_HDR_VARINT: srl_read_varint_into(aTHX_ dec, into, container, track_it); break;
1748 141226           case SRL_HDR_ZIGZAG: srl_read_zigzag_into(aTHX_ dec, into, container, track_it); break;
1749              
1750 10812           case SRL_HDR_FLOAT: srl_read_float(aTHX_ dec, into); break;
1751 152640           case SRL_HDR_DOUBLE: srl_read_double(aTHX_ dec, into); break;
1752 0           case SRL_HDR_LONG_DOUBLE: srl_read_long_double(aTHX_ dec, into); break;
1753              
1754 3           case SRL_HDR_TRUE: sv_setsv(into, &PL_sv_yes); break;
1755 3           case SRL_HDR_FALSE: sv_setsv(into, &PL_sv_no); break;
1756              
1757             case SRL_HDR_CANONICAL_UNDEF: /* fallthrough (XXX: is this right?)*/
1758             case SRL_HDR_UNDEF:
1759             {
1760 52010 100         if (container && SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_USE_UNDEF)){
    50          
1761 0           SvREFCNT_dec(into);
1762 0           *container= &PL_sv_undef;
1763 0 0         if ( track_it )
1764 0           srl_track_sv(aTHX_ dec, track_it, *container);
1765             } else {
1766 52010           sv_setsv(into, &PL_sv_undef);
1767             }
1768             }
1769 52010           break;
1770              
1771 422391           case SRL_HDR_BINARY: srl_read_string(aTHX_ dec, 0, into); break;
1772 101859           case SRL_HDR_STR_UTF8: srl_read_string(aTHX_ dec, 1, into); break;
1773              
1774 13           case SRL_HDR_WEAKEN: srl_read_weaken(aTHX_ dec, into); is_ref=1; break;
1775 955869           case SRL_HDR_REFN: srl_read_refn(aTHX_ dec, into); is_ref=1; break;
1776 218167           case SRL_HDR_REFP: srl_read_refp(aTHX_ dec, into); is_ref=1; break;
1777             case SRL_HDR_OBJECT_FREEZE:
1778 25481           case SRL_HDR_OBJECT: srl_read_object(aTHX_ dec, into, tag, 0); is_ref=1; break;
1779             case SRL_HDR_OBJECTV_FREEZE:
1780 645           case SRL_HDR_OBJECTV: srl_read_objectv(aTHX_ dec, into, tag); is_ref=1; break;
1781 19800           case SRL_HDR_COPY: srl_read_copy(aTHX_ dec, into); break;
1782 0           case SRL_HDR_EXTEND: srl_read_extend(aTHX_ dec, into); break;
1783 95648           case SRL_HDR_HASH: srl_read_hash(aTHX_ dec, into, 0); break;
1784 320832           case SRL_HDR_ARRAY: srl_read_array(aTHX_ dec, into, 0); break;
1785 17184           case SRL_HDR_REGEXP: srl_read_regexp(aTHX_ dec, into); break;
1786             case SRL_HDR_ALIAS:
1787             {
1788             UV offset;
1789             SV *alias;
1790 96686 50         if (!container)
1791 0           SRL_RDR_ERROR(dec->pbuf, "ALIAS tag not inside container, corrupt packet?");
1792 96686           offset= srl_read_varint_uv_offset(aTHX_ dec->pbuf," while reading ALIAS tag");
1793 96686           alias= srl_fetch_item(aTHX_ dec, offset, "ALIAS");
1794             #ifdef FOLLOW_REFERENCES_IF_NOT_STASHED
1795             if (!alias) alias= srl_follow_refp_alias_reference(aTHX_ dec, offset);
1796             #endif
1797 96685           SvREFCNT_inc(alias);
1798 96685           SvREFCNT_dec(into);
1799 96685           *container= alias;
1800 96685 50         if (track_it)
1801 0           srl_track_sv(aTHX_ dec, track_it, alias);
1802 96685           return;
1803             }
1804             break;
1805             case SRL_HDR_PAD: /* no op */
1806 3 50         while (SRL_RDR_NOT_DONE(dec->pbuf) && *dec->buf.pos == SRL_HDR_PAD)
    50          
1807 0           dec->buf.pos++;
1808 3           goto read_again;
1809             break;
1810             default:
1811 225332 100         if (tag & SRL_HDR_TRACK_FLAG) {
1812 225330           tag= tag & ~SRL_HDR_TRACK_FLAG;
1813 225330           track_it = dec->buf.pos-1;
1814 225330           srl_track_sv(aTHX_ dec, track_it, into);
1815 225330           goto read_tag;
1816             } else {
1817 2           SRL_RDR_ERROR_UNEXPECTED(dec->pbuf, tag, " single value");
1818             }
1819             break;
1820             }
1821              
1822             /* they want us to set all SVs readonly, or only the non-ref */
1823             #define SUPPORT_READONLY 1
1824             #if SUPPORT_READONLY
1825 4267509 100         if ( expect_false(dec->flags_readonly) )
1826             {
1827 317166 100         if (
1828 35 100         dec->flags_readonly == 1 || !is_ref
1829             ) {
1830 317148 100         if (is_ref && !SvREADONLY(SvRV(into)) ) {
    100          
1831 62592           SvREADONLY_on(SvRV(into));
1832             }
1833 317148 100         if (!SvREADONLY(into)) {
1834 315253           SvREADONLY_on(into);
1835             }
1836             }
1837             }
1838             #endif
1839              
1840              
1841 4267509           return;
1842             }