File Coverage

Clone.xs
Criterion Covered Total %
statement 106 129 82.1
branch 51 74 68.9
condition n/a
subroutine n/a
pod n/a
total 157 203 77.3


line stmt bran cond sub pod time code
1             #include
2              
3             #include "EXTERN.h"
4             #include "perl.h"
5             #include "XSUB.h"
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             static SV *hv_clone (SV *, SV *, HV *, int);
25             static SV *av_clone (SV *, SV *, HV *, int);
26             static SV *sv_clone (SV *, HV *, int);
27             static SV *rv_clone (SV *, HV *, int);
28              
29             #ifdef DEBUG_CLONE
30             #define TRACEME(a) printf("%s:%d: ",__FUNCTION__, __LINE__) && printf a;
31             #else
32             #define TRACEME(a)
33             #endif
34              
35             static SV *
36 23           hv_clone (SV * ref, SV * target, HV* hseen, int depth)
37             {
38 23           HV *clone = (HV *) target;
39 23           HV *self = (HV *) ref;
40 23           HE *next = NULL;
41 23 50         int recur = depth ? depth - 1 : 0;
42              
43             assert(SvTYPE(ref) == SVt_PVHV);
44              
45             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
46              
47 23           hv_iterinit (self);
48 55 100         while ((next = hv_iternext (self)))
49             {
50 32           SV *key = hv_iterkeysv (next);
51             TRACEME(("clone item %s\n", SvPV_nolen(key) ));
52 32           hv_store_ent (clone, key,
53             sv_clone (hv_iterval (self, next), hseen, recur), 0);
54             }
55              
56             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
57 23           return (SV *) clone;
58             }
59              
60             static SV *
61 14           av_clone (SV * ref, SV * target, HV* hseen, int depth)
62             {
63 14           AV *clone = (AV *) target;
64 14           AV *self = (AV *) ref;
65             SV **svp;
66 14           SV *val = NULL;
67 14           I32 arrlen = 0;
68 14           int i = 0;
69 14 50         int recur = depth ? depth - 1 : 0;
70              
71             assert(SvTYPE(ref) == SVt_PVAV);
72              
73             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
74              
75             /* The following is a holdover from a very old version */
76             /* possible cause of memory leaks */
77             /* if ( (SvREFCNT(ref) > 1) ) */
78             /* CLONE_STORE(ref, (SV *)clone); */
79              
80 14           arrlen = av_len (self);
81 14           av_extend (clone, arrlen);
82              
83 41 100         for (i = 0; i <= arrlen; i++)
84             {
85 27           svp = av_fetch (self, i, 0);
86 27 50         if (svp)
87 27           av_store (clone, i, sv_clone (*svp, hseen, recur));
88             }
89              
90             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
91 14           return (SV *) clone;
92             }
93              
94             static SV *
95 0           rv_clone (SV * ref, HV* hseen, int depth)
96             {
97 0           SV *clone = NULL;
98 0           SV *rv = NULL;
99              
100             assert(SvROK(ref));
101              
102             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
103              
104 0 0         if (!SvROK (ref))
105 0           return NULL;
106              
107 0 0         if (sv_isobject (ref))
108             {
109 0           clone = newRV_noinc(sv_clone (SvRV(ref), hseen, depth));
110 0           sv_2mortal (sv_bless (clone, SvSTASH (SvRV (ref))));
111             }
112             else
113 0           clone = newRV_inc(sv_clone (SvRV(ref), hseen, depth));
114            
115             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
116 0           return clone;
117             }
118              
119             static SV *
120 161           sv_clone (SV * ref, HV* hseen, int depth)
121             {
122 161           SV *clone = ref;
123 161           SV **seen = NULL;
124             UV visible;
125 161           int magic_ref = 0;
126              
127 161 50         if (!ref)
128             {
129             TRACEME(("NULL\n"));
130 0           return NULL;
131             }
132              
133             #if PERL_REVISION >= 5 && PERL_VERSION > 8
134             /* This is a hack for perl 5.9.*, save everything */
135             /* until I find out why mg_find is no longer working */
136 161           visible = 1;
137             #else
138             visible = (SvREFCNT(ref) > 1) || (SvMAGICAL(ref) && mg_find(ref, '<'));
139             #endif
140              
141             TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
142              
143 161 100         if (depth == 0)
144 6           return SvREFCNT_inc(ref);
145              
146 155 50         if (visible && (seen = CLONE_FETCH(ref)))
    100          
147             {
148             TRACEME(("fetch ref (0x%x)\n", ref));
149 13           return SvREFCNT_inc(*seen);
150             }
151              
152             TRACEME(("switch: (0x%x)\n", ref));
153 142           switch (SvTYPE (ref))
154             {
155             case SVt_NULL: /* 0 */
156             TRACEME(("sv_null\n"));
157 3           clone = newSVsv (ref);
158 3           break;
159             case SVt_IV: /* 1 */
160             TRACEME(("int scalar\n"));
161             case SVt_NV: /* 2 */
162             TRACEME(("double scalar\n"));
163 75           clone = newSVsv (ref);
164 75           break;
165             #if PERL_VERSION <= 10
166             case SVt_RV: /* 3 */
167             TRACEME(("ref scalar\n"));
168             clone = newSVsv (ref);
169             break;
170             #endif
171             case SVt_PV: /* 4 */
172             TRACEME(("string scalar\n"));
173             /*
174             * Note: when using a Debug Perl with READONLY_COW
175             * we cannot do 'sv_buf_to_rw + sv_buf_to_ro' as these APIs calls are not exported
176             */
177             #if defined(SV_COW_REFCNT_MAX) && !defined(PERL_DEBUG_READONLY_COW)
178             /* only for simple PVs unblessed */
179 14 100         if ( SvIsCOW(ref) && !SvOOK(ref) && SvLEN(ref) > 0 ) {
    50          
    50          
180              
181 22 50         if ( CowREFCNT(ref) < (SV_COW_REFCNT_MAX - 1) ) {
182             /* cannot use newSVpv_share as this going to use a new PV we do not want to clone it */
183             /* create a fresh new PV */
184 11           clone = newSV(0);
185 11           sv_upgrade(clone, SVt_PV);
186 11           SvPOK_on(clone);
187 11           SvIsCOW_on(clone);
188              
189             /* points the str slot to the COWed one */
190 11           SvPV_set(clone, SvPVX(ref) );
191 11           CowREFCNT(ref)++;
192              
193             /* preserve cur, len, flags and utf8 flag */
194 11           SvCUR_set(clone, SvCUR(ref));
195 11           SvLEN_set(clone, SvLEN(ref));
196 11           SvFLAGS(clone) = SvFLAGS(ref); /* preserve all the flags from the original SV */
197              
198 11 50         if (SvUTF8(ref))
199 11           SvUTF8_on(clone);
200             } else {
201             /* we are above SV_COW_REFCNT_MAX, create a new SvPV but preserve the COW */
202 0           clone = newSVsv (ref);
203 0           SvIsCOW_on(clone);
204 0           CowREFCNT(clone) = 0; /* set the CowREFCNT to 0 */
205             }
206              
207             } else {
208 3           clone = newSVsv (ref);
209             }
210             #else
211             clone = newSVsv (ref);
212             #endif
213 14           break;
214             case SVt_PVIV: /* 5 */
215             TRACEME (("PVIV double-type\n"));
216             case SVt_PVNV: /* 6 */
217             TRACEME (("PVNV double-type\n"));
218 3           clone = newSVsv (ref);
219 3           break;
220             case SVt_PVMG: /* 7 */
221             TRACEME(("magic scalar\n"));
222 7           clone = newSVsv (ref);
223 7           break;
224             case SVt_PVAV: /* 10 */
225 15           clone = (SV *) newAV();
226 15           break;
227             case SVt_PVHV: /* 11 */
228 24           clone = (SV *) newHV();
229 24           break;
230             #if PERL_VERSION <= 8
231             case SVt_PVBM: /* 8 */
232             #elif PERL_VERSION >= 11
233             case SVt_REGEXP: /* 8 */
234             #endif
235             case SVt_PVLV: /* 9 */
236             case SVt_PVCV: /* 12 */
237             case SVt_PVGV: /* 13 */
238             case SVt_PVFM: /* 14 */
239             case SVt_PVIO: /* 15 */
240             TRACEME(("default: type = 0x%x\n", SvTYPE (ref)));
241 1           clone = SvREFCNT_inc(ref); /* just return the ref */
242 1           break;
243             default:
244 0           croak("unknown type: 0x%x", SvTYPE(ref));
245             }
246              
247             /**
248             * It is *vital* that this is performed *before* recursion,
249             * to properly handle circular references. cb 2001-02-06
250             */
251              
252 142 50         if ( visible && ref != clone )
    100          
253 141 50         CLONE_STORE(ref,clone);
254              
255             /*
256             * We'll assume (in the absence of evidence to the contrary) that A) a
257             * tied hash/array doesn't store its elements in the usual way (i.e.
258             * the mg->mg_object(s) take full responsibility for them) and B) that
259             * references aren't tied.
260             *
261             * If theses assumptions hold, the three options below are mutually
262             * exclusive.
263             *
264             * More precisely: 1 & 2 are probably mutually exclusive; 2 & 3 are
265             * definitely mutually exclusive; we have to test 1 before giving 2
266             * a chance; and we'll assume that 1 & 3 are mutually exclusive unless
267             * and until we can be test-cased out of our delusion.
268             *
269             * chocolateboy: 2001-05-29
270             */
271            
272             /* 1: TIED */
273 142 100         if (SvMAGICAL(ref) )
274             {
275             MAGIC* mg;
276 6           MGVTBL *vtable = 0;
277              
278 12 100         for (mg = SvMAGIC(ref); mg; mg = mg->mg_moremagic)
279             {
280 6           SV *obj = (SV *) NULL;
281             /* we don't want to clone a qr (regexp) object */
282             /* there are probably other types as well ... */
283             TRACEME(("magic type: %c\n", mg->mg_type));
284             /* Some mg_obj's can be null, don't bother cloning */
285 6 100         if ( mg->mg_obj != NULL )
286             {
287 4           switch (mg->mg_type)
288             {
289             case 'r': /* PERL_MAGIC_qr */
290 0           obj = mg->mg_obj;
291 0           break;
292             case 't': /* PERL_MAGIC_taint */
293             case '<': /* PERL_MAGIC_backref */
294             case '@': /* PERL_MAGIC_arylen_p */
295 0           continue;
296             break;
297             case 'P': /* PERL_MAGIC_tied */
298             case 'p': /* PERL_MAGIC_tiedelem */
299             case 'q': /* PERL_MAGIC_tiedscalar */
300 3           magic_ref++;
301             /* fall through */
302             default:
303 4           obj = sv_clone(mg->mg_obj, hseen, -1);
304             }
305             } else {
306             TRACEME(("magic object for type %c in NULL\n", mg->mg_type));
307             }
308              
309             { /* clone the mg_ptr pv */
310 6           char *mg_ptr = mg->mg_ptr; /* default */
311              
312 6 100         if (mg->mg_len >= 0) { /* copy the pv */
313 4 50         if (mg_ptr) {
314 0           Newxz(mg_ptr, mg->mg_len+1, char); /* add +1 for the NULL at the end? */
315 4           Copy(mg->mg_ptr, mg_ptr, mg->mg_len, char);
316             }
317 2 50         } else if (mg->mg_len == HEf_SVKEY) {
318             /* let's share the SV for now */
319 0           SvREFCNT_inc((SV*)mg->mg_ptr);
320             /* maybe we also want to clone the SV... */
321             //if (mg_ptr) mg->mg_ptr = (char*) sv_clone((SV*)mg->mg_ptr, hseen, -1);
322 2 50         } else if (mg->mg_len == -1 && mg->mg_type == PERL_MAGIC_utf8) { /* copy the cache */
    50          
323 3 100         if (mg->mg_ptr) {
324             STRLEN *cache;
325 1           Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
326 1           mg_ptr = (char *) cache;
327 1           Copy(mg->mg_ptr, mg_ptr, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
328             }
329 0 0         } else if ( mg->mg_ptr != NULL) {
330 0           croak("Unsupported magic_ptr clone");
331             }
332              
333             /* this is plain old magic, so do the same thing */
334 6           sv_magic(clone,
335             obj,
336             mg->mg_type,
337             mg_ptr,
338             mg->mg_len);
339              
340             }
341             }
342             /* major kludge - why does the vtable for a qr type need to be null? */
343 6 50         if ( (mg = mg_find(clone, 'r')) )
344 0           mg->mg_virtual = (MGVTBL *) NULL;
345             }
346             /* 2: HASH/ARRAY - (with 'internal' elements) */
347 142 100         if ( magic_ref )
348             {
349             ;;
350             }
351 139 100         else if ( SvTYPE(ref) == SVt_PVHV )
352 23           clone = hv_clone (ref, clone, hseen, depth);
353 116 100         else if ( SvTYPE(ref) == SVt_PVAV )
354 14           clone = av_clone (ref, clone, hseen, depth);
355             /* 3: REFERENCE (inlined for speed) */
356 102 100         else if (SvROK (ref))
357             {
358             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
359 64           SvREFCNT_dec(SvRV(clone));
360 64           SvRV(clone) = sv_clone (SvRV(ref), hseen, depth); /* Clone the referent */
361 64 100         if (sv_isobject (ref))
362             {
363 20           sv_bless (clone, SvSTASH (SvRV (ref)));
364             }
365 64 100         if (SvWEAKREF(ref)) {
366 3           sv_rvweaken(clone);
367             }
368             }
369              
370             TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
371 142           return clone;
372             }
373              
374             MODULE = Clone PACKAGE = Clone
375              
376             PROTOTYPES: ENABLE
377              
378             void
379             clone(self, depth=-1)
380             SV *self
381             int depth
382             PREINIT:
383 34           SV *clone = &PL_sv_undef;
384 34           HV *hseen = newHV();
385             PPCODE:
386             TRACEME(("ref = 0x%x\n", self));
387 34           clone = sv_clone(self, hseen, depth);
388 34           hv_clear(hseen); /* Free HV */
389 34           SvREFCNT_dec((SV *)hseen);
390 34 50         EXTEND(SP,1);
391 34           PUSHs(sv_2mortal(clone));