File Coverage

Clone.xs
Criterion Covered Total %
statement 190 230 82.6
branch 120 204 58.8
condition n/a
subroutine n/a
pod n/a
total 310 434 71.4


line stmt bran cond sub pod time code
1             #include
2              
3             #include "EXTERN.h"
4             #include "perl.h"
5             #include "XSUB.h"
6             #include "ppport.h"
7              
8             #define CLONE_KEY(x) ((char *) &x)
9              
10             /* Maximum safe recursion depth before switching to iterative mode.
11             * Each nesting level of [[[...]]] consumes ~3 C stack frames in the
12             * recursive clone path (sv_clone for RV + sv_clone for AV + av_clone).
13             * The rdepth counter increments once per sv_clone() call, so the
14             * nesting level is roughly rdepth/2, using ~450 bytes of stack each.
15             *
16             * Windows has a 1 MB default thread stack; Cygwin typically 2 MB.
17             * Linux/macOS default to 8 MB but some CPAN smokers and containers
18             * may have 4 MB or less available after Perl/harness overhead.
19             *
20             * MAX_DEPTH=2000 on Windows/Cygwin -> ~1000 nesting levels -> ~450 KB.
21             * MAX_DEPTH=4000 elsewhere -> ~2000 nesting levels -> ~900 KB.
22             * (GH #77: 32000 was too aggressive — caused SEGV on CPAN smokers.) */
23             #if defined(_WIN32) || defined(__CYGWIN__)
24             #define MAX_DEPTH 2000
25             #else
26             #define MAX_DEPTH 4000
27             #endif
28              
29             #define CLONE_STORE(x,y) \
30             do { \
31             if (!hv_store(hseen, CLONE_KEY(x), PTRSIZE, SvREFCNT_inc(y), 0)) { \
32             SvREFCNT_dec(y); /* Restore the refcount */ \
33             croak("Can't store clone in seen hash (hseen)"); \
34             } \
35             else { \
36             TRACEME(("storing ref = 0x%x clone = 0x%x\n", ref, clone)); \
37             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone))); \
38             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref))); \
39             } \
40             } while (0)
41              
42             #define CLONE_FETCH(x) (hv_fetch(hseen, CLONE_KEY(x), PTRSIZE, 0))
43              
44             static SV *hv_clone (SV *, SV *, HV *, int, int, AV *);
45             static SV *av_clone (SV *, SV *, HV *, int, int, AV *);
46             static SV *sv_clone (SV *, HV *, int, int, AV *);
47             static SV *av_clone_iterative(SV *, HV *, int, AV *);
48              
49             #ifdef DEBUG_CLONE
50             #define TRACEME(a) printf("%s:%d: ",__FUNCTION__, __LINE__) && printf a;
51             #else
52             #define TRACEME(a)
53             #endif
54              
55             /* Check whether an mg_obj is a threads::shared::tie instance.
56             * The mg_obj is an RV pointing to a blessed PVMG. (GH #18) */
57             static int
58 3           is_threads_shared_tie(SV *obj)
59             {
60             HV *stash;
61 3 50         if (!obj || !SvROK(obj) || !SvOBJECT(SvRV(obj)))
    50          
    50          
62 0           return 0;
63 3           stash = SvSTASH(SvRV(obj));
64 6 50         return stash && HvNAME(stash)
    50          
    0          
    50          
    50          
    50          
65 9 50         && strEQ(HvNAME(stash), "threads::shared::tie");
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
66             }
67              
68             static SV *
69 59           hv_clone (SV * ref, SV * target, HV* hseen, int depth, int rdepth, AV * weakrefs)
70             {
71 59           HV *clone = (HV *) target;
72 59           HV *self = (HV *) ref;
73 59           HE *next = NULL;
74 59 50         int recur = depth ? depth - 1 : 0;
75              
76             assert(SvTYPE(ref) == SVt_PVHV);
77              
78             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
79              
80             /* Pre-size the target hash to avoid incremental resizing */
81 59 50         if (HvKEYS(self) > 0)
    100          
82 55 50         hv_ksplit(clone, HvKEYS(self));
83              
84 59           hv_iterinit (self);
85 141 100         while ((next = hv_iternext (self)))
86             {
87             I32 klen;
88 82           char *kpv = hv_iterkey(next, &klen);
89 82           SV *val = sv_clone(hv_iterval(self, next), hseen, recur, rdepth, weakrefs);
90             /* Use hv_iterkey + HeHASH to avoid allocating a mortal SV per key.
91             * Negate klen for UTF-8 keys per Perl API convention. */
92 82 100         if (HeKUTF8(next))
93 1           klen = -klen;
94             TRACEME(("clone item %.*s\n", (int)(klen > 0 ? klen : -klen), kpv));
95 82           hv_store(clone, kpv, klen, val, HeHASH(next));
96             }
97              
98             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
99 59           return (SV *) clone;
100             }
101              
102             static SV *
103 2           av_clone_iterative(SV * ref, HV* hseen, int rdepth, AV * weakrefs)
104             {
105             AV *self;
106             AV *root_clone;
107             AV *tail;
108             SV *current_ref;
109 2           SV **seen = NULL;
110             SV **svp;
111             I32 arrlen;
112             I32 i;
113              
114 2 50         if (!ref) return NULL;
115              
116 2           self = (AV *)ref;
117              
118             /* Check if we've already cloned this array */
119 2 50         if ((seen = CLONE_FETCH(ref))) {
120 0           return SvREFCNT_inc(*seen);
121             }
122              
123             /* Create new array and store it in seen hash immediately */
124 2           root_clone = newAV();
125 2 50         CLONE_STORE(ref, (SV *)root_clone);
126              
127             /* Optimized path for deeply nested single-element arrays:
128             * [[[...]]] chains are unrolled iteratively to avoid stack overflow.
129             * Each nesting level is an AV with one element (an RV to the next AV). */
130 2 100         if (av_len(self) == 0) {
131 1           svp = av_fetch(self, 0, 0);
132 1 50         if (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVAV) {
    50          
    50          
133 1           tail = root_clone;
134 1           current_ref = *svp;
135              
136             /* Walk the chain: each step creates one AV and one RV link */
137 3001 50         while (current_ref && SvROK(current_ref) &&
138 9000 50         SvTYPE(SvRV(current_ref)) == SVt_PVAV &&
139 3000           av_len((AV*)SvRV(current_ref)) == 0) {
140 2999           AV *new_av = newAV();
141 2999           SV *inner_sv = SvRV(current_ref);
142              
143 2999           av_store(tail, 0, newRV_noinc((SV*)new_av));
144 2999 50         CLONE_STORE(inner_sv, (SV*)new_av);
145              
146             /* Advance to the next element in the chain */
147 2999           svp = av_fetch((AV*)inner_sv, 0, 0);
148 2999 50         if (!svp) break;
149 2999           current_ref = *svp;
150 2999           tail = new_av;
151             }
152              
153             /* Handle the final element (leaf or non-matching structure) */
154 1 50         if (current_ref) {
155 1 50         if (SvROK(current_ref) &&
156 2 50         SvTYPE(SvRV(current_ref)) == SVt_PVAV) {
157             /* Final AV — clone it iteratively too */
158 1           SV *leaf = av_clone_iterative(SvRV(current_ref),
159             hseen, rdepth, weakrefs);
160 1           av_store(tail, 0, newRV_noinc(leaf));
161 0 0         } else if (SvROK(current_ref)) {
162 0           av_store(tail, 0,
163             sv_clone(current_ref, hseen, 1, rdepth, weakrefs));
164             } else {
165 0           av_store(tail, 0, newSVsv(current_ref));
166             }
167             }
168              
169 1           return (SV*)root_clone;
170             }
171              
172             /* Single non-array element */
173 0 0         if (svp) {
174 0           av_store(root_clone, 0,
175             sv_clone(*svp, hseen, 1, rdepth, weakrefs));
176             }
177 0           return (SV*)root_clone;
178             }
179              
180             /* General case: array with multiple elements */
181 1           arrlen = av_len(self);
182 1           av_extend(root_clone, arrlen);
183              
184             {
185 1           SV **dst = AvARRAY(root_clone);
186 1 50         for (i = 0; i <= arrlen; i++) {
187 0           svp = av_fetch(self, i, 0);
188 0 0         if (svp) {
189 0           dst[i] = sv_clone(*svp, hseen, 1, rdepth, weakrefs);
190             }
191             }
192 1           AvFILLp(root_clone) = arrlen;
193             }
194              
195 1           return (SV*)root_clone;
196             }
197              
198             static SV *
199 4028           av_clone (SV * ref, SV * target, HV* hseen, int depth, int rdepth, AV * weakrefs)
200             {
201             AV *clone;
202             AV *self;
203             SV **svp;
204             SV **dst;
205 4028           I32 arrlen = 0;
206             I32 i;
207             int recur;
208              
209             /* For very deep structures, use the iterative approach */
210 4028 50         if (depth == 0) {
211 0           return av_clone_iterative(ref, hseen, rdepth, weakrefs);
212             }
213              
214 4028           clone = (AV *) target;
215 4028           self = (AV *) ref;
216 4028           recur = depth > 0 ? depth - 1 : -1;
217              
218             assert(SvTYPE(ref) == SVt_PVAV);
219              
220             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
221              
222 4028           arrlen = av_len(self);
223 4028           av_extend(clone, arrlen);
224              
225             /* Use av_fetch on the source (may be magical/tied) but write
226             * directly to the target's AvARRAY (we just created it, no magic). */
227 4028           dst = AvARRAY(clone);
228 8092 100         for (i = 0; i <= arrlen; i++) {
229 4064           svp = av_fetch(self, i, 0);
230 4064 50         if (svp) {
231 4064           dst[i] = sv_clone(*svp, hseen, recur, rdepth, weakrefs);
232             }
233             }
234 4028           AvFILLp(clone) = arrlen;
235              
236             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
237 4028           return (SV *) clone;
238             }
239              
240             static SV *
241 308379           sv_clone (SV * ref, HV* hseen, int depth, int rdepth, AV * weakrefs)
242             {
243             SV *clone;
244 308379           SV **seen = NULL;
245             UV visible;
246 308379           int magic_ref = 0;
247              
248 308379 50         if (!ref)
249 0           return NULL;
250              
251 308379           rdepth++;
252              
253             /* Check for deep recursion and switch to iterative mode.
254             * A deeply nested arrayref like [[[...]]] alternates between RV and AV
255             * at each level, consuming ~3 C stack frames per nesting level.
256             * On Windows (1MB default stack), this overflows around depth 2000.
257             * When we exceed MAX_DEPTH, handle both AV and RV-to-AV cases. */
258 308379 100         if (rdepth > MAX_DEPTH) {
259 1 50         if (SvTYPE(ref) == SVt_PVAV) {
260 0           return av_clone_iterative(ref, hseen, rdepth, weakrefs);
261             }
262             /* For RVs pointing to AVs, follow the reference and use the
263             * iterative path -- this is the common case for [[[...]]] */
264 1 50         if (SvROK(ref) && SvTYPE(SvRV(ref)) == SVt_PVAV) {
    50          
265 1           SV *clone_av = av_clone_iterative(SvRV(ref), hseen, rdepth, weakrefs);
266 1           SV *clone_rv = newRV_noinc(clone_av);
267 1 50         if (SvOBJECT(SvRV(ref)))
268 0           sv_bless(clone_rv, SvSTASH(SvRV(ref)));
269 1           return clone_rv;
270             }
271             /* For other types, just return a reference to avoid stack overflow */
272 0           return SvREFCNT_inc(ref);
273             }
274              
275 308378           clone = ref;
276              
277             #if PERL_REVISION >= 5 && PERL_VERSION > 8
278             /* This is a hack for perl 5.9.*, save everything */
279             /* until I find out why mg_find is no longer working */
280 308378           visible = 1;
281             #else
282             visible = (SvREFCNT(ref) > 1) || (SvMAGICAL(ref) && mg_find(ref, '<'));
283             #endif
284              
285             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
286              
287 308378 100         if (depth == 0)
288 6           return SvREFCNT_inc(ref);
289              
290 308372 50         if (visible && (seen = CLONE_FETCH(ref)))
    100          
291             {
292             TRACEME(("fetch ref (0x%x)\n", ref));
293 22           return SvREFCNT_inc(*seen);
294             }
295              
296             /* threads::shared tiedelem PVLVs are proxies to shared data.
297             * They would normally be returned by SvREFCNT_inc (like other PVLVs),
298             * but that shares the proxy — mutations go back to the shared var.
299             * Copy through magic to get a plain unshared value. (GH #18) */
300 308350 100         if (SvTYPE(ref) == SVt_PVLV && SvMAGICAL(ref))
    50          
301             {
302             MAGIC *mg;
303 400008 100         for (mg = SvMAGIC(ref); mg; mg = mg->mg_moremagic)
304             {
305 200004 50         if ((mg->mg_type == PERL_MAGIC_tiedelem
306 200004 50         || mg->mg_type == PERL_MAGIC_tiedscalar)
307 0 0         && is_threads_shared_tie(mg->mg_obj))
308             {
309             TRACEME(("threads::shared tiedelem PVLV — copy value\n"));
310 0           clone = newSVsv(ref);
311 0 0         if (visible && ref != clone)
    0          
312 0 0         CLONE_STORE(ref, clone);
313 0           return clone;
314             }
315             }
316             }
317              
318             TRACEME(("switch: (0x%x)\n", ref));
319 308350           switch (SvTYPE (ref))
320             {
321 100003           case SVt_NULL: /* 0 */
322             TRACEME(("sv_null\n"));
323 100003           clone = newSVsv (ref);
324 100003           break;
325 4170           case SVt_IV: /* 1 */
326             TRACEME(("int scalar\n"));
327             case SVt_NV: /* 2 */
328             TRACEME(("double scalar\n"));
329 4170           clone = newSVsv (ref);
330 4170           break;
331             #if PERL_VERSION <= 10
332             case SVt_RV: /* 3 */
333             TRACEME(("ref scalar\n"));
334             clone = newSVsv (ref);
335             break;
336             #endif
337 55           case SVt_PV: /* 4 */
338             TRACEME(("string scalar\n"));
339             /*
340             * Note: when using a Debug Perl with READONLY_COW
341             * we cannot do 'sv_buf_to_rw + sv_buf_to_ro' as these APIs calls are not exported
342             */
343             #if defined(SV_COW_REFCNT_MAX) && !defined(PERL_DEBUG_READONLY_COW)
344             /* only for simple PVs unblessed */
345 55 100         if ( SvIsCOW(ref) && !SvOOK(ref) && SvLEN(ref) > 0 ) {
    50          
    100          
346              
347 40 100         if ( CowREFCNT(ref) < (SV_COW_REFCNT_MAX - 1) ) {
348             /* cannot use newSVpv_share as this going to use a new PV we do not want to clone it */
349             /* create a fresh new PV */
350 38           clone = newSV(0);
351 38           sv_upgrade(clone, SVt_PV);
352 38           SvPOK_on(clone);
353 38           SvIsCOW_on(clone);
354              
355             /* points the str slot to the COWed one */
356 38           SvPV_set(clone, SvPVX(ref) );
357 38           CowREFCNT(ref)++;
358              
359             /* preserve cur, len, and value-relevant flags */
360 38           SvCUR_set(clone, SvCUR(ref));
361 38           SvLEN_set(clone, SvLEN(ref));
362 38 100         if (SvUTF8(ref))
363 1           SvUTF8_on(clone);
364             } else {
365             /* we are above SV_COW_REFCNT_MAX, create a new SvPV but preserve the COW */
366 2           clone = newSVsv (ref);
367 2           SvIsCOW_on(clone);
368 2           CowREFCNT(clone) = 0; /* set the CowREFCNT to 0 */
369             }
370              
371             } else {
372 15           clone = newSVsv (ref);
373             }
374             #else
375             clone = newSVsv (ref);
376             #endif
377 55           break;
378 11           case SVt_PVIV: /* 5 */
379             TRACEME (("PVIV double-type\n"));
380             case SVt_PVNV: /* 6 */
381             TRACEME (("PVNV double-type\n"));
382 11           clone = newSVsv (ref);
383 11           break;
384 8           case SVt_PVMG: /* 7 */
385             TRACEME(("magic scalar\n"));
386 8           clone = newSVsv (ref);
387 8           break;
388 4029           case SVt_PVAV: /* 10 */
389 4029           clone = (SV *) newAV();
390 4029           break;
391 60           case SVt_PVHV: /* 11 */
392 60           clone = (SV *) newHV();
393 60           break;
394             #if PERL_VERSION <= 8
395             case SVt_PVBM: /* 8 */
396             #elif PERL_VERSION >= 11
397 200014           case SVt_REGEXP: /* 8 */
398             #endif
399             case SVt_PVLV: /* 9 */
400             case SVt_PVCV: /* 12 */
401             case SVt_PVGV: /* 13 */
402             case SVt_PVFM: /* 14 */
403             case SVt_PVIO: /* 15 */
404             TRACEME(("default: type = 0x%x\n", SvTYPE (ref)));
405 200014           clone = SvREFCNT_inc(ref); /* just return the ref */
406 200014           break;
407 0           default:
408 0           croak("unknown type: 0x%x", SvTYPE(ref));
409             }
410              
411             /**
412             * It is *vital* that this is performed *before* recursion,
413             * to properly handle circular references. cb 2001-02-06
414             */
415              
416 308350 50         if ( visible && ref != clone )
    100          
417 108336 50         CLONE_STORE(ref,clone);
418              
419             /* If clone == ref (e.g. for PVLV, PVGV, PVCV types), we just
420             * incremented the refcount — skip all internal cloning to avoid
421             * adding duplicate magic entries or corrupting the original SV.
422             * (fixes GH #42: memory leak when cloning non-existent hash values) */
423 308350 100         if (ref == clone)
424 200014           return clone;
425              
426             /*
427             * We'll assume (in the absence of evidence to the contrary) that A) a
428             * tied hash/array doesn't store its elements in the usual way (i.e.
429             * the mg->mg_object(s) take full responsibility for them) and B) that
430             * references aren't tied.
431             *
432             * If theses assumptions hold, the three options below are mutually
433             * exclusive.
434             *
435             * More precisely: 1 & 2 are probably mutually exclusive; 2 & 3 are
436             * definitely mutually exclusive; we have to test 1 before giving 2
437             * a chance; and we'll assume that 1 & 3 are mutually exclusive unless
438             * and until we can be test-cased out of our delusion.
439             *
440             * chocolateboy: 2001-05-29
441             */
442              
443             /* 1: TIED */
444 108336 100         if (SvMAGICAL(ref) )
445             {
446             MAGIC* mg;
447 6           int has_qr = 0;
448              
449 12 100         for (mg = SvMAGIC(ref); mg; mg = mg->mg_moremagic)
450             {
451 6           SV *obj = (SV *) NULL;
452             TRACEME(("magic type: %c\n", mg->mg_type));
453              
454             /* PERL_MAGIC_ext: opaque XS data, handle before the mg_obj check
455             * since ext magic often has mg_obj == NULL (GH #27, GH #16) */
456 6 100         if (mg->mg_type == '~')
457             {
458             #if defined(MGf_DUP) && defined(sv_magicext)
459             /* If the ext magic has a dup callback (e.g. Math::BigInt::GMP),
460             * clone it properly via sv_magicext + svt_dup.
461             * Otherwise skip it (e.g. DBI handles have no dup).
462             * Note: we check only for svt_dup presence, not MGf_DUP flag,
463             * because some older XS modules (e.g. Math::BigInt::GMP on
464             * Perl 5.22) provide svt_dup without setting MGf_DUP. (GH #76) */
465 1 50         if (mg->mg_virtual && mg->mg_virtual->svt_dup)
    0          
466             {
467             MAGIC *new_mg;
468 0           new_mg = sv_magicext(clone, mg->mg_obj,
469             mg->mg_type, mg->mg_virtual,
470             mg->mg_ptr, mg->mg_len);
471 0           new_mg->mg_flags |= MGf_DUP;
472             /* CLONE_PARAMS is NULL since we are not in a thread clone.
473             * Known callers (e.g. Math::BigInt::GMP) ignore it. */
474 0           mg->mg_virtual->svt_dup(aTHX_ new_mg, NULL);
475             }
476             #endif
477 1           continue;
478             }
479              
480             /* threads::shared uses tie magic ('P') with a threads::shared::tie
481             * object, and shared_scalar magic ('n'/'N') for scalars.
482             * Cloning these produces invalid tie objects that crash on access.
483             * Strip the sharing magic so hv_clone/av_clone can iterate through
484             * the tie to read the actual data. (GH #18) */
485 5 50         if (mg->mg_type == PERL_MAGIC_shared_scalar
486 5 50         || mg->mg_type == PERL_MAGIC_shared)
487 0           continue;
488              
489             /* Some mg_obj's can be null, don't bother cloning */
490 5 100         if ( mg->mg_obj != NULL )
491             {
492 3           switch (mg->mg_type)
493             {
494 0           case 'r': /* PERL_MAGIC_qr */
495 0           obj = mg->mg_obj;
496 0           has_qr = 1;
497 0           break;
498 0           case 't': /* PERL_MAGIC_taint */
499             case '<': /* PERL_MAGIC_backref */
500             case '@': /* PERL_MAGIC_arylen_p */
501 0           continue;
502             break;
503 3           case 'P': /* PERL_MAGIC_tied */
504             case 'p': /* PERL_MAGIC_tiedelem */
505             case 'q': /* PERL_MAGIC_tiedscalar */
506             /* threads::shared::tie objects are not real tie objects --
507             * skip them so the clone becomes a plain unshared copy.
508             * The data will be read through the tie during hv_clone/av_clone. */
509 3 50         if (is_threads_shared_tie(mg->mg_obj))
510 0           continue;
511 3           magic_ref++;
512             /* fall through */
513 3           default:
514 3           obj = sv_clone(mg->mg_obj, hseen, -1, rdepth, weakrefs);
515             }
516             } else {
517             TRACEME(("magic object for type %c in NULL\n", mg->mg_type));
518             }
519              
520             { /* clone the mg_ptr pv */
521 5           char *mg_ptr = mg->mg_ptr; /* default */
522              
523 5 100         if (mg->mg_len >= 0) { /* copy the pv */
524 3 50         if (mg_ptr) {
525 0           Newxz(mg_ptr, mg->mg_len+1, char);
526 0           Copy(mg->mg_ptr, mg_ptr, mg->mg_len, char);
527             }
528 2 50         } else if (mg->mg_len == HEf_SVKEY) {
529             /* let's share the SV for now */
530 0           SvREFCNT_inc((SV*)mg->mg_ptr);
531 2 50         } else if (mg->mg_len == -1 && mg->mg_type == PERL_MAGIC_utf8) { /* copy the cache */
    50          
532 2 100         if (mg->mg_ptr) {
533             STRLEN *cache;
534 1           Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
535 1           mg_ptr = (char *) cache;
536 1           Copy(mg->mg_ptr, mg_ptr, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
537             }
538 0 0         } else if ( mg->mg_ptr != NULL) {
539 0           croak("Unsupported magic_ptr clone");
540             }
541              
542 5           sv_magic(clone,
543             obj,
544             mg->mg_type,
545             mg_ptr,
546             mg->mg_len);
547              
548             }
549             }
550             /* Null the qr vtable -- avoid mg_find traversal if we already know */
551 6 50         if (has_qr && (mg = mg_find(clone, 'r')))
    0          
552 0           mg->mg_virtual = (MGVTBL *) NULL;
553             }
554             /* 2: HASH/ARRAY - (with 'internal' elements) */
555 108336 100         if ( magic_ref )
556             {
557             ;;
558             }
559 108333 100         else if ( SvTYPE(ref) == SVt_PVHV )
560 59           clone = hv_clone (ref, clone, hseen, depth, rdepth, weakrefs);
561 108274 100         else if ( SvTYPE(ref) == SVt_PVAV )
562 4028           clone = av_clone (ref, clone, hseen, depth, rdepth, weakrefs);
563             /* 3: REFERENCE (inlined for speed) */
564 104246 100         else if (SvROK (ref))
565             {
566             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
567 4138           SvREFCNT_dec(SvRV(clone));
568 4138           SvRV(clone) = sv_clone (SvRV(ref), hseen, depth, rdepth, weakrefs); /* Clone the referent */
569 4138 100         if (SvOBJECT(SvRV(ref)))
570             {
571 54           sv_bless (clone, SvSTASH (SvRV (ref)));
572             }
573 4138 100         if (SvWEAKREF(ref)) {
574             /* Defer weakening until after the entire clone graph is built.
575             * sv_rvweaken decrements the referent's refcount, which can
576             * destroy it if no other strong references exist yet.
577             * By deferring, we ensure all strong references are in place
578             * before any weakening occurs. (fixes GH #15) */
579 9           av_push(weakrefs, SvREFCNT_inc_simple_NN(clone));
580             }
581             }
582              
583             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
584 108336           return clone;
585             }
586              
587             MODULE = Clone PACKAGE = Clone
588              
589             PROTOTYPES: ENABLE
590              
591             void
592             clone(self, depth=-1)
593             SV *self
594             int depth
595             PREINIT:
596 300092           SV *clone = &PL_sv_undef;
597 300092           HV *hseen = newHV();
598 300092 100         AV *weakrefs = newAV();
599             PPCODE:
600             TRACEME(("ref = 0x%x\n", self));
601 300092           clone = sv_clone(self, hseen, depth, 0, weakrefs);
602             /* Now apply deferred weakening (GH #15).
603             * All strong references in the clone graph are established,
604             * so it is safe to weaken references without destroying referents. */
605             {
606             I32 i;
607 300092           I32 len = av_len(weakrefs);
608 300101 100         for (i = 0; i <= len; i++) {
609 9           SV **svp = av_fetch(weakrefs, i, 0);
610 9 50         if (svp && *svp && SvROK(*svp)) {
    50          
    50          
611 9           sv_rvweaken(*svp);
612             }
613             }
614             }
615 300092           hv_clear(hseen); /* Free HV */
616 300092           SvREFCNT_dec((SV *)hseen);
617 300092           SvREFCNT_dec((SV *)weakrefs);
618 300092 50         EXTEND(SP,1);
619 300092           PUSHs(sv_2mortal(clone));