File Coverage

Clone.xs
Criterion Covered Total %
statement 63 191 32.9
branch 31 172 18.0
condition n/a
subroutine n/a
pod n/a
total 94 363 25.9


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT /* we want efficiency */
2              
3             #include "xshelper.h"
4              
5             #define MAX_DEPTH 32000
6              
7             #define CLONE_KEY(x) ((char *) &x)
8              
9             #define CLONE_STORE(x,y) \
10             do { \
11             if (!hv_store(hseen, CLONE_KEY(x), PTRSIZE, SvREFCNT_inc(y), 0)) { \
12             SvREFCNT_dec(y); /* Restore the refcount */ \
13             croak("Can't store clone in seen hash (hseen)"); \
14             } \
15             else { \
16             TRACEME(("storing ref = 0x%x clone = 0x%x\n", ref, clone)); \
17             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone))); \
18             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref))); \
19             } \
20             } while (0)
21              
22             #define CLONE_FETCH(x) (hv_fetch(hseen, CLONE_KEY(x), PTRSIZE, 0))
23              
24             #define PUSH_WEAKREFS(weakrefs, val) av_push( weakrefs, SvREFCNT_inc_simple_NN(val) )
25              
26             #define HANDLE_WEAKREFS(weakrefs) \
27             do { \
28             I32 i; \
29             I32 len = av_len((weakrefs)); \
30             for ( i = 0; i <= len; i++ ) { \
31             SV **svp = av_fetch( (weakrefs), i, 0 ); \
32             if ( svp && *svp && SvROK(*svp) ) sv_rvweaken(*svp); \
33             } \
34             SvREFCNT_dec( (SV *)(weakrefs) ); \
35             } while (0)
36              
37             static SV *hv_clone (pTHX_ SV *, SV *, HV *, int, int, AV *);
38             static SV *av_clone (pTHX_ SV *, SV *, HV *, int, int, AV *);
39             static SV *sv_clone (pTHX_ SV *, HV *, int, int, AV *);
40             /* static SV *rv_clone (pTHX_ SV *, HV *, int, int, AV *); */
41             static SV *av_clone_iterative(pTHX_ SV *, HV *, int, AV *);
42              
43             #ifdef DEBUG_CLONE
44             #define TRACEME(a) printf("%s:%d: ",__FUNCTION__, __LINE__) && printf a;
45             #else
46             #define TRACEME(a)
47             #endif
48              
49             /* Check whether an mg_obj is a threads::shared::tie instance.
50             * The mg_obj is an RV pointing to a blessed PVMG. (GH #18) */
51             static int
52 0           is_threads_shared_tie(SV *obj) {
53 0 0         if ( !obj || !SvROK(obj) || !SvOBJECT(SvRV(obj)) )
    0          
    0          
54 0           return 0;
55              
56 0           HV* stash = SvSTASH( SvRV(obj) );
57 0 0         if ( ! stash ) return 0;
58              
59 0 0         const char *name = HvNAME(stash);
    0          
    0          
    0          
    0          
    0          
60 0 0         return ( name && strcmp( name, "threads::shared::tie" ) == 0 );
    0          
61             }
62              
63             static SV*
64 5           hv_clone (pTHX_ SV* ref, SV* target, HV* hseen, int depth, int rdepth, AV* weakrefs) {
65 5           HV *clone = (HV *) target;
66 5           HV *self = (HV *) ref;
67 5           HE *next = NULL;
68 5 50         int recur = depth ? depth - 1 : 0;
69              
70             assert(SvTYPE(ref) == SVt_PVHV);
71              
72             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
73              
74 5           hv_iterinit (self);
75 12 100         while ((next = hv_iternext(self))) {
76 7           SV *key = hv_iterkeysv(next);
77             TRACEME(("clone item %s\n", SvPV_nolen(key) ));
78 7           hv_store_ent(clone, key, sv_clone(aTHX_ hv_iterval(self, next), hseen, recur, rdepth, weakrefs), 0);
79             }
80              
81             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
82 5           return (SV *) clone;
83             }
84              
85             static SV*
86 0           av_clone_iterative (pTHX_ SV* ref, HV* hseen, int rdepth, AV* weakrefs) {
87 0 0         if (!ref) return NULL;
88              
89 0           AV *self = (AV *) ref;
90 0           SV **seen = NULL;
91              
92             /* Check if we've already cloned this array */
93 0 0         if (( seen = CLONE_FETCH(ref) )) {
94 0           return SvREFCNT_inc(*seen);
95             }
96              
97             /* Create new array and store it in seen hash immediately */
98 0           AV *clone = newAV();
99 0 0         CLONE_STORE(ref, (SV *)clone);
100              
101             /* Special handling for single-element arrays that might be deeply nested */
102 0 0         if ( av_len(self) == 0 ) {
103 0           SV **elem = av_fetch( self, 0, 0 );
104 0 0         if ( elem && SvROK(*elem) && SvTYPE(SvRV(*elem)) == SVt_PVAV ) {
    0          
    0          
105             /* Handle deeply nested array structure iteratively */
106 0           SV *current = *elem;
107 0           AV *current_av = (AV*)SvRV(current);
108 0 0         while ( current && SvROK(current) && SvTYPE( SvRV(current) ) == SVt_PVAV && av_len( (AV*)SvRV(current) ) == 0 ) {
    0          
    0          
    0          
109 0           AV *new_av = newAV();
110 0           av_store( clone, 0, newRV_noinc( (SV*)new_av ) );
111             /* Get the next element */
112 0           SV **next_elem = av_fetch( current_av, 0, 0 );
113 0 0         if ( ! next_elem ) break;
114 0           current = *next_elem;
115 0 0         current_av = SvROK(current) ? (AV*)SvRV(current) : NULL;
116             /* Store in seen hash to handle circular references */
117 0 0         CLONE_STORE( SvRV(*elem), (SV*)new_av );
118 0           clone = new_av;
119             }
120             /* Handle the final element if it exists */
121 0 0         if ( current ) {
122 0 0         if ( SvROK(current) ) {
123 0           av_store( clone, 0, sv_clone(aTHX_ current, hseen, 1, rdepth, weakrefs) );
124             }
125             else {
126 0           av_store( clone, 0, newSVsv(current) );
127             }
128             }
129             }
130 0 0         else if ( elem ) {
131             /* Handle single non-array element */
132 0           av_store( clone, 0, sv_clone( aTHX_ *elem, hseen, 1, rdepth, weakrefs ) );
133             }
134             }
135             else {
136             /* Handle normal array cloning */
137 0           I32 arrlen = av_len(self);
138             I32 i;
139 0           av_extend( clone, arrlen );
140 0 0         for ( i = 0; i <= arrlen; i++ ) {
141 0           SV **svp = av_fetch( self, i, 0 );
142 0 0         if ( svp ) {
143 0           SV *new_sv = sv_clone( aTHX_ *svp, hseen, 1, rdepth, weakrefs );
144 0 0         if ( ! av_store( clone, i, new_sv ) ) {
145 0           SvREFCNT_dec(new_sv);
146             }
147             }
148             }
149             }
150 0           return (SV*)clone;
151             }
152              
153             static SV*
154 1           av_clone (pTHX_ SV* ref, SV* target, HV* hseen, int depth, int rdepth, AV* weakrefs)
155             {
156             /* For very deep structures, use the iterative approach */
157 1 50         if ( depth == 0 ) {
158 0           return av_clone_iterative( aTHX_ ref, hseen, rdepth, weakrefs );
159             }
160              
161 1           AV *clone = (AV *) target;
162 1           AV *self = (AV *) ref;
163             SV **svp;
164 1           I32 arrlen = 0;
165 1           int recur = depth > 0 ? depth - 1 : -1;
166              
167             assert(SvTYPE(ref) == SVt_PVAV);
168              
169             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
170              
171 1           arrlen = av_len(self);
172 1           av_extend(clone, arrlen);
173              
174             I32 i;
175 4 100         for ( i = 0; i <= arrlen; i++ ) {
176 3           svp = av_fetch( self, i, 0 );
177 3 50         if (svp) {
178 3           SV *new_sv = sv_clone( aTHX_ *svp, hseen, recur, rdepth, weakrefs );
179 3 50         if ( ! av_store( clone, i, new_sv ) ) {
180 0           SvREFCNT_dec(new_sv);
181             }
182             }
183             }
184              
185             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
186 1           return (SV *) clone;
187             }
188              
189             /*
190             static SV *
191             rv_clone (pTHX_ SV * ref, HV* hseen, int depth, int rdepth, AV * weakrefs) {
192             SV *clone = NULL;
193              
194             assert(SvROK(ref));
195              
196             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
197              
198             if (!SvROK(ref)) return NULL;
199              
200             if ( sv_isobject(ref) ) {
201             clone = newRV_noinc(sv_clone(aTHX_ SvRV(ref), hseen, depth));
202             sv_2mortal(sv_bless(clone, SvSTASH(SvRV(ref))));
203             }
204             else {
205             clone = newRV_inc(sv_clone(aTHX_ SvRV(ref), hseen, depth));
206             }
207              
208             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
209             return clone;
210             }
211             */
212              
213             static SV*
214 23           sv_clone (pTHX_ SV* ref, HV* hseen, int depth, int rdepth, AV* weakrefs) {
215              
216 23           rdepth++;
217              
218             /* Check for deep recursion and switch to iterative mode */
219 23 50         if ( rdepth > MAX_DEPTH ) {
220 0 0         if ( SvTYPE(ref) == SVt_PVAV ) {
221 0           return av_clone_iterative( aTHX_ ref, hseen, rdepth, weakrefs );
222             }
223             /* For other types, just return a reference to avoid stack overflow */
224 0           return SvREFCNT_inc(ref);
225             }
226              
227 23           SV *clone = ref;
228 23           SV **seen = NULL;
229             UV visible;
230 23           int magic_ref = 0;
231              
232 23 50         if ( ! ref ) {
233             TRACEME(("NULL\n"));
234 0           return NULL;
235             }
236              
237             #if PERL_REVISION >= 5 && PERL_VERSION > 8
238             /* This is a hack for perl 5.9.*, save everything */
239             /* until I find out why mg_find is no longer working */
240 23           visible = 1;
241             #else
242             visible = ( SvREFCNT(ref) > 1) || (SvMAGICAL(ref) && mg_find(ref, '<') );
243             #endif
244              
245             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
246              
247 23 50         if ( depth == 0 )
248 0           return SvREFCNT_inc(ref);
249              
250 23 50         if ( visible && (seen = CLONE_FETCH(ref)) ) {
    50          
251             TRACEME(("fetch ref (0x%x)\n", ref));
252 0           return SvREFCNT_inc(*seen);
253             }
254              
255             /* threads::shared tiedelem PVLVs are proxies to shared data.
256             * They would normally be returned by SvREFCNT_inc (like other PVLVs),
257             * but that shares the proxy — mutations go back to the shared var.
258             * Copy through magic to get a plain unshared value. */
259 23 50         if ( SvTYPE(ref) == SVt_PVLV && SvMAGICAL(ref) ) {
    0          
260             MAGIC *mg;
261 0 0         for ( mg = SvMAGIC(ref); mg; mg = mg->mg_moremagic ) {
262 0 0         if ( (mg->mg_type == PERL_MAGIC_tiedelem || mg->mg_type == PERL_MAGIC_tiedscalar)
    0          
263 0 0         && is_threads_shared_tie(mg->mg_obj) ) {
264             TRACEME(("threads::shared tiedelem PVLV — copy value\n"));
265 0           clone = newSVsv(ref);
266 0 0         if ( visible && ref != clone ) CLONE_STORE(ref, clone);
    0          
    0          
267 0           return clone;
268             }
269             }
270             }
271              
272             TRACEME(("switch: (0x%x)\n", ref));
273 23           switch ( SvTYPE(ref) ) {
274 0           case SVt_NULL:
275             TRACEME(("sv_null\n"));
276 0           clone = newSVsv(ref);
277 0           break;
278 16           case SVt_IV:
279             TRACEME(("int scalar\n"));
280             case SVt_NV:
281             TRACEME(("double scalar\n"));
282 16           clone = newSVsv(ref);
283 16           break;
284             #if PERL_VERSION <= 10
285             case SVt_RV:
286             TRACEME(("ref scalar\n"));
287             clone = newSVsv(ref);
288             break;
289             #endif
290 0           case SVt_PV:
291             TRACEME(("string scalar\n"));
292             #if defined(SV_COW_REFCNT_MAX) && !defined(PERL_DEBUG_READONLY_COW)
293             /* only for simple PVs unblessed */
294 0 0         if ( SvIsCOW(ref) && !SvOOK(ref) && SvLEN(ref) > 0 ) {
    0          
    0          
295 0 0         if ( CowREFCNT(ref) < (SV_COW_REFCNT_MAX - 1) ) {
296             /* cannot use newSVpv_share as this going to use a new PV we do not want to clone it */
297             /* create a fresh new PV */
298 0           clone = newSV(0);
299 0           sv_upgrade( clone, SVt_PV );
300 0           SvPOK_on(clone);
301 0           SvIsCOW_on(clone);
302              
303             /* points the str slot to the COWed one */
304 0           SvPV_set( clone, SvPVX(ref) );
305 0           CowREFCNT(ref)++;
306              
307             /* preserve cur, len, flags and utf8 flag */
308 0           SvCUR_set( clone, SvCUR(ref) );
309 0           SvLEN_set( clone, SvLEN(ref) );
310 0           SvFLAGS(clone) = SvFLAGS(ref); /* preserve all the flags from the original SV */
311              
312 0 0         if ( SvUTF8(ref) )
313 0           SvUTF8_on(clone);
314             }
315             else {
316             /* we are above SV_COW_REFCNT_MAX, create a new SvPV but preserve the COW */
317 0           clone = newSVsv(ref);
318 0           SvIsCOW_on(clone);
319 0           CowREFCNT(clone) = 0; /* set the CowREFCNT to 0 */
320             }
321             }
322             else {
323 0           clone = newSVsv(ref);
324             }
325             #else
326             clone = newSVsv(ref);
327             #endif
328 0           break;
329 0           case SVt_PVIV:
330             TRACEME (("PVIV double-type\n"));
331             case SVt_PVNV:
332             TRACEME (("PVNV double-type\n"));
333 0           clone = newSVsv(ref);
334 0           break;
335 0           case SVt_PVMG:
336             TRACEME(("magic scalar\n"));
337 0           clone = newSVsv(ref);
338 0           break;
339 1           case SVt_PVAV:
340 1           clone = (SV *) newAV();
341 1           break;
342 5           case SVt_PVHV:
343 5           clone = (SV *) newHV();
344 5           break;
345             #if PERL_VERSION <= 8
346             case SVt_PVBM:
347             #elif PERL_VERSION >= 11
348 1           case SVt_REGEXP:
349             #endif
350             case SVt_PVLV:
351             case SVt_PVCV:
352             case SVt_PVGV:
353             case SVt_PVFM:
354             case SVt_PVIO:
355             TRACEME(("default: type = 0x%x\n", SvTYPE(ref)));
356 1           clone = SvREFCNT_inc(ref); /* just return the ref */
357 1           break;
358 0           default:
359 0           croak( "unknown type: 0x%x", SvTYPE(ref) );
360             }
361              
362             /**
363             * It is *vital* that this is performed *before* recursion,
364             * to properly handle circular references. cb 2001-02-06
365             */
366 23 50         if ( visible && ref != clone ) CLONE_STORE( ref, clone );
    100          
    50          
367              
368             /* If clone == ref (e.g. for PVLV, PVGV, PVCV types), we just
369             * incremented the refcount — skip all internal cloning to avoid
370             * adding duplicate magic entries or corrupting the original SV.
371             * (fixes GH #42: memory leak when cloning non-existent hash values) */
372 23 100         if ( ref == clone ) return clone;
373              
374             /*
375             * We'll assume (in the absence of evidence to the contrary) that A) a
376             * tied hash/array doesn't store its elements in the usual way (i.e.
377             * the mg->mg_object(s) take full responsibility for them) and B) that
378             * references aren't tied.
379             *
380             * If theses assumptions hold, the three options below are mutually
381             * exclusive.
382             *
383             * More precisely: 1 & 2 are probably mutually exclusive; 2 & 3 are
384             * definitely mutually exclusive; we have to test 1 before giving 2
385             * a chance; and we'll assume that 1 & 3 are mutually exclusive unless
386             * and until we can be test-cased out of our delusion.
387             *
388             * chocolateboy: 2001-05-29
389             */
390            
391             /* 1: TIED */
392 22 50         if (SvMAGICAL(ref)) {
393             MAGIC* mg;
394             /* MGVTBL *vtable = 0; */
395              
396 0 0         for ( mg = SvMAGIC(ref); mg; mg = mg->mg_moremagic ) {
397 0           SV *obj = (SV *) NULL;
398             /* we don't want to clone a qr (regexp) object */
399             /* there are probably other types as well ... */
400             TRACEME(("magic type: %c\n", mg->mg_type));
401              
402             /* PERL_MAGIC_ext: opaque XS data, handle before the mg_obj check
403             * since ext magic often has mg_obj == NULL (GH #27, GH #16) */
404 0 0         if ( mg->mg_type == '~' ) {
405             #if defined(MGf_DUP) && defined(sv_magicext)
406             /* If the ext magic has a dup callback (e.g. Math::BigInt::GMP),
407             * clone it properly via sv_magicext + svt_dup.
408             * Otherwise skip it (e.g. DBI handles have no dup). */
409 0 0         if ( mg->mg_virtual && mg->mg_virtual->svt_dup && (mg->mg_flags & MGf_DUP) ) {
    0          
    0          
410             MAGIC *new_mg;
411 0           new_mg = sv_magicext( clone, mg->mg_obj, mg->mg_type, mg->mg_virtual, mg->mg_ptr, mg->mg_len );
412 0           new_mg->mg_flags |= MGf_DUP;
413             /* CLONE_PARAMS is NULL since we are not in a thread clone.
414             * Known callers (e.g. Math::BigInt::GMP) ignore it. */
415 0           mg->mg_virtual->svt_dup( aTHX_ new_mg, NULL );
416             }
417             #endif
418 0           continue;
419             }
420              
421             /* threads::shared uses tie magic ('P') with a threads::shared::tie
422             * object, and shared_scalar magic ('n'/'N') for scalars.
423             * Cloning these produces invalid tie objects that crash on access.
424             * Strip the sharing magic so hv_clone/av_clone can iterate through
425             * the tie to read the actual data. */
426 0 0         if ( mg->mg_type == PERL_MAGIC_shared_scalar || mg->mg_type == PERL_MAGIC_shared )
    0          
427 0           continue;
428              
429             /* Some mg_obj's can be null, don't bother cloning */
430 0 0         if ( mg->mg_obj != NULL ) {
431 0           switch ( mg->mg_type ) {
432 0           case 'r': /* PERL_MAGIC_qr */
433 0           obj = mg->mg_obj;
434 0           break;
435 0           case 't': /* PERL_MAGIC_taint */
436             case '<': /* PERL_MAGIC_backref */
437             case '@': /* PERL_MAGIC_arylen_p */
438 0           continue;
439             break;
440 0           case 'P': /* PERL_MAGIC_tied */
441             case 'p': /* PERL_MAGIC_tiedelem */
442             case 'q': /* PERL_MAGIC_tiedscalar */
443             /* threads::shared::tie objects are not real tie objects —
444             * skip them so the clone becomes a plain unshared copy.
445             * The data will be read through the tie during hv_clone/av_clone. */
446 0 0         if ( is_threads_shared_tie(mg->mg_obj) ) continue;
447 0           magic_ref++;
448             /* fall through */
449 0           default:
450 0           obj = sv_clone( aTHX_ mg->mg_obj, hseen, -1, rdepth, weakrefs );
451             }
452             }
453             else {
454             TRACEME(("magic object for type %c in NULL\n", mg->mg_type));
455             }
456              
457             { /* clone the mg_ptr pv */
458 0           char *mg_ptr = mg->mg_ptr; /* default */
459              
460 0 0         if ( mg->mg_len >= 0 ) { /* copy the pv */
461 0 0         if ( mg_ptr ) {
462 0           Newxz( mg_ptr, mg->mg_len+1, char ); /* add +1 for the NULL at the end? */
463 0           Copy( mg->mg_ptr, mg_ptr, mg->mg_len, char );
464             }
465             }
466 0 0         else if ( mg->mg_len == HEf_SVKEY ) {
467             /* let's share the SV for now */
468 0           SvREFCNT_inc( (SV*)mg->mg_ptr );
469             /* maybe we also want to clone the SV... */
470             /* if (mg_ptr) mg->mg_ptr = (char*) sv_clone(aTHX_ (SV*)mg->mg_ptr, hseen, -1); */
471             }
472 0 0         else if ( mg->mg_len == -1 && mg->mg_type == PERL_MAGIC_utf8 ) { /* copy the cache */
    0          
473 0 0         if ( mg->mg_ptr ) {
474             STRLEN *cache;
475 0           Newxz( cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN );
476 0           mg_ptr = (char *) cache;
477 0           Copy( mg->mg_ptr, mg_ptr, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN );
478             }
479             }
480 0 0         else if ( mg->mg_ptr != NULL) {
481 0           croak("Unsupported magic_ptr clone");
482             }
483              
484             /* this is plain old magic, so do the same thing */
485 0           sv_magic( clone, obj, mg->mg_type, mg_ptr, mg->mg_len );
486              
487             }
488             }
489             /* major kludge - why does the vtable for a qr type need to be null? */
490 0 0         if (( mg = mg_find(clone, 'r') ))
491 0           mg->mg_virtual = (MGVTBL *) NULL;
492             }
493              
494             /* 2: HASH/ARRAY - (with 'internal' elements) */
495 22 50         if ( magic_ref ) {
496             ;;
497             }
498 22 100         else if ( SvTYPE(ref) == SVt_PVHV )
499 5           clone = hv_clone( aTHX_ ref, clone, hseen, depth, rdepth, weakrefs );
500 17 100         else if ( SvTYPE(ref) == SVt_PVAV )
501 1           clone = av_clone( aTHX_ ref, clone, hseen, depth, rdepth, weakrefs );
502             /* 3: REFERENCE (inlined for speed) */
503 16 100         else if ( SvROK(ref) ) {
504             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
505 8           SvREFCNT_dec( SvRV(clone) );
506 8           SvRV(clone) = sv_clone( aTHX_ SvRV(ref), hseen, depth, rdepth, weakrefs ); /* Clone the referent */
507 8 100         if ( sv_isobject(ref) ) {
508 1           sv_bless( clone, SvSTASH( SvRV(ref) ) );
509             }
510 8 50         if ( SvWEAKREF(ref) ) {
511             /* Defer weakening until after the entire clone graph is built.
512             * sv_rvweaken decrements the referent's refcount, which can
513             * destroy it if no other strong references exist yet.
514             * By deferring, we ensure all strong references are in place
515             * before any weakening occurs. */
516 0           PUSH_WEAKREFS( weakrefs, clone );
517             }
518             }
519              
520             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
521 22           return clone;
522             }