@@ -406,6 +406,22 @@ size_t __arrayPad(size_t size, const TypeInfo tinext) nothrow pure @trusted
406
406
return size > MAXMEDSIZE ? LARGEPAD : ((size > MAXSMALLSIZE ? MEDPAD : SMALLPAD ) + structTypeInfoSize(tinext));
407
407
}
408
408
409
+ /**
410
+ clear padding that might not be zeroed by the GC (it assumes it is within the
411
+ requested size from the start, but it is actually at the end of the allocated block)
412
+ */
413
+ private void __arrayClearPad (ref BlkInfo info, size_t arrsize, size_t padsize) nothrow pure
414
+ {
415
+ import core.stdc.string ;
416
+ if (padsize > MEDPAD && ! (info.attr & BlkAttr.NO_SCAN ) && info.base)
417
+ {
418
+ if (info.size < PAGESIZE )
419
+ memset(info.base + arrsize, 0 , padsize);
420
+ else
421
+ memset(info.base, 0 , LARGEPREFIX );
422
+ }
423
+ }
424
+
409
425
/**
410
426
allocate an array memory block by applying the proper padding and
411
427
assigning block attributes if not inherited from the existing block
@@ -426,7 +442,10 @@ BlkInfo __arrayAlloc(size_t arrsize, const TypeInfo ti, const TypeInfo tinext) n
426
442
uint attr = (! (tinext.flags & 1 ) ? BlkAttr.NO_SCAN : 0 ) | BlkAttr.APPENDABLE ;
427
443
if (typeInfoSize)
428
444
attr |= BlkAttr.STRUCTFINAL | BlkAttr.FINALIZE ;
429
- return GC .qalloc(padded_size, attr, tinext);
445
+
446
+ auto bi = GC .qalloc(padded_size, attr, tinext);
447
+ __arrayClearPad(bi, arrsize, padsize);
448
+ return bi;
430
449
}
431
450
432
451
BlkInfo __arrayAlloc (size_t arrsize, ref BlkInfo info, const TypeInfo ti, const TypeInfo tinext)
@@ -436,14 +455,17 @@ BlkInfo __arrayAlloc(size_t arrsize, ref BlkInfo info, const TypeInfo ti, const
436
455
if (! info.base)
437
456
return __arrayAlloc (arrsize, ti, tinext);
438
457
458
+ immutable padsize = __arrayPad(arrsize, tinext);
439
459
bool overflow;
440
- auto padded_size = addu(arrsize, __arrayPad(arrsize, tinext) , overflow);
460
+ auto padded_size = addu(arrsize, padsize , overflow);
441
461
if (overflow)
442
462
{
443
463
return BlkInfo ();
444
464
}
445
465
446
- return GC .qalloc(padded_size, info.attr, tinext);
466
+ auto bi = GC .qalloc(padded_size, info.attr, tinext);
467
+ __arrayClearPad(bi, arrsize, padsize);
468
+ return bi;
447
469
}
448
470
449
471
/**
@@ -1096,15 +1118,19 @@ extern (C) void* _d_newitemU(in TypeInfo _ti)
1096
1118
auto ti = unqualify(_ti);
1097
1119
auto flags = ! (ti.flags & 1 ) ? BlkAttr.NO_SCAN : 0 ;
1098
1120
immutable tiSize = structTypeInfoSize(ti);
1099
- immutable size = ti.tsize + tiSize;
1121
+ immutable itemSize = ti.tsize;
1122
+ immutable size = itemSize + tiSize;
1100
1123
if (tiSize)
1101
1124
flags |= BlkAttr.STRUCTFINAL | BlkAttr.FINALIZE ;
1102
1125
1103
1126
auto blkInf = GC .qalloc(size, flags, ti);
1104
1127
auto p = blkInf.base;
1105
1128
1106
1129
if (tiSize)
1130
+ {
1131
+ * cast (TypeInfo * )(p + itemSize) = null ; // the GC might not have cleared this area
1107
1132
* cast (TypeInfo * )(p + blkInf.size - tiSize) = cast () ti;
1133
+ }
1108
1134
1109
1135
return p;
1110
1136
}
@@ -2678,6 +2704,80 @@ deprecated unittest
2678
2704
}
2679
2705
}
2680
2706
2707
+ // test struct dtor handling not causing false pointers
2708
+ unittest
2709
+ {
2710
+ if (! callStructDtorsDuringGC)
2711
+ return ;
2712
+
2713
+ // for 64-bit, allocate a struct of size 40
2714
+ static struct S
2715
+ {
2716
+ size_t [4 ] data;
2717
+ S* ptr4;
2718
+ }
2719
+ auto p1 = new S;
2720
+ auto p2 = new S;
2721
+ p2.ptr4 = p1;
2722
+
2723
+ // a struct with a dtor with size 32, but the dtor will cause
2724
+ // allocation to be larger by a pointer
2725
+ static struct A
2726
+ {
2727
+ size_t [3 ] data;
2728
+ S* ptr3;
2729
+
2730
+ ~this () {}
2731
+ }
2732
+
2733
+ GC .free(p2);
2734
+ auto a = new A; // reuse same memory
2735
+ if (cast (void * )a is cast (void * )p2) // reusage not guaranteed
2736
+ {
2737
+ auto ptr = cast (S** )(a + 1 );
2738
+ assert (* ptr != p1); // still same data as p2.ptr4?
2739
+ }
2740
+
2741
+ // small array
2742
+ static struct SArr
2743
+ {
2744
+ void * [10 ] data;
2745
+ }
2746
+ auto arr1 = new SArr;
2747
+ arr1.data[] = p1;
2748
+ GC .free(arr1);
2749
+
2750
+ // allocates 2*A.sizeof + (void*).sizeof (TypeInfo) + 1 (array length)
2751
+ auto arr2 = new A[2 ];
2752
+ if (cast (void * )arr1 is cast (void * )arr2.ptr) // reusage not guaranteed
2753
+ {
2754
+ auto ptr = cast (S** )(arr2.ptr + 2 );
2755
+ assert (* ptr != p1); // still same data as p2.ptr4?
2756
+ }
2757
+
2758
+ // large array
2759
+ static struct LArr
2760
+ {
2761
+ void * [1023 ] data;
2762
+ }
2763
+ auto larr1 = new LArr;
2764
+ larr1.data[] = p1;
2765
+ GC .free(larr1);
2766
+
2767
+ auto larr2 = new S[255 ];
2768
+ if (cast (void * )larr1 is cast (void * )larr2.ptr - LARGEPREFIX ) // reusage not guaranteed
2769
+ {
2770
+ auto ptr = cast (S** )larr1;
2771
+ assert (ptr[0 ] != p1); // 16 bytes array header
2772
+ assert (ptr[1 ] != p1);
2773
+ version (D_LP64 ) {} else
2774
+ {
2775
+ assert (ptr[2 ] != p1);
2776
+ assert (ptr[3 ] != p1);
2777
+ }
2778
+ }
2779
+ }
2780
+
2681
2781
// test class finalizers exception handling
2682
2782
unittest
2683
2783
{
0 commit comments