@@ -412,6 +412,8 @@ class ConservativeGC : GC
412
412
if (pool)
413
413
{
414
414
p = sentinel_sub(p);
415
+ if (p != pool.findBase(p))
416
+ return 0 ;
415
417
auto biti = cast (size_t )(p - pool.baseAddr) >> pool.shiftBy;
416
418
417
419
oldb = pool.getBits(biti);
@@ -438,6 +440,8 @@ class ConservativeGC : GC
438
440
if (pool)
439
441
{
440
442
p = sentinel_sub(p);
443
+ if (p != pool.findBase(p))
444
+ return 0 ;
441
445
auto biti = cast (size_t )(p - pool.baseAddr) >> pool.shiftBy;
442
446
443
447
oldb = pool.getBits(biti);
@@ -465,6 +469,8 @@ class ConservativeGC : GC
465
469
if (pool)
466
470
{
467
471
p = sentinel_sub(p);
472
+ if (p != pool.findBase(p))
473
+ return 0 ;
468
474
auto biti = cast (size_t )(p - pool.baseAddr) >> pool.shiftBy;
469
475
470
476
oldb = pool.getBits(biti);
@@ -854,12 +860,10 @@ class ConservativeGC : GC
854
860
855
861
sentinel_Invariant(p);
856
862
p = sentinel_sub(p);
857
- biti = cast (size_t )(p - pool.baseAddr) >> pool.shiftBy;
858
-
859
- pool.clrBits(biti, ~ BlkAttr.NONE );
860
863
861
864
if (pool.isLargeObject) // if large alloc
862
865
{
866
+ biti = cast (size_t )(p - pool.baseAddr) >> pool.ShiftBy.Large;
863
867
assert (bin == B_PAGE );
864
868
auto lpool = cast (LargeObjectPool* ) pool;
865
869
@@ -869,15 +873,21 @@ class ConservativeGC : GC
869
873
lpool.freePages(pagenum, npages);
870
874
}
871
875
else
872
- { // Add to free list
876
+ {
877
+ biti = cast (size_t )(p - pool.baseAddr) >> pool.ShiftBy.Small;
878
+ if (pool.freebits.test (biti))
879
+ return ;
880
+ // Add to free list
873
881
List * list = cast (List* )p;
874
882
875
883
debug (MEMSTOMP ) memset(p, 0xF2 , binsize[bin]);
876
884
877
885
list.next = gcx.bucket[bin];
878
886
list.pool = pool;
879
887
gcx.bucket[bin] = list;
888
+ pool.freebits.set(biti);
880
889
}
890
+ pool.clrBits(biti, ~ BlkAttr.NONE );
881
891
882
892
gcx.log_free(sentinel_add(p));
883
893
}
@@ -1416,6 +1426,9 @@ struct Gcx
1416
1426
{
1417
1427
for (auto list = cast (List* )bucket[i]; list; list = list.next)
1418
1428
{
1429
+ auto pool = list.pool;
1430
+ auto biti = cast (size_t )(cast (void * )list - pool.baseAddr) >> Pool.ShiftBy.Small;
1431
+ assert (pool.freebits.test(biti));
1419
1432
}
1420
1433
}
1421
1434
}
@@ -1546,35 +1559,7 @@ struct Gcx
1546
1559
1547
1560
pool = findPool(p);
1548
1561
if (pool)
1549
- {
1550
- size_t offset = cast (size_t )(p - pool.baseAddr);
1551
- size_t pn = offset / PAGESIZE ;
1552
- Bins bin = cast (Bins)pool.pagetable[pn];
1553
-
1554
- // Adjust bit to be at start of allocated memory block
1555
- if (bin < B_NUMSMALL )
1556
- {
1557
- return pool.baseAddr + baseOffset(offset, bin);
1558
- }
1559
- else if (bin == B_PAGE )
1560
- {
1561
- return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE - 1 )));
1562
- }
1563
- else if (bin == B_PAGEPLUS )
1564
- {
1565
- size_t pageOffset = pool.bPageOffsets[pn];
1566
- offset -= pageOffset * PAGESIZE ;
1567
- pn -= pageOffset;
1568
-
1569
- return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE - 1 )));
1570
- }
1571
- else
1572
- {
1573
- // we are in a B_FREE page
1574
- assert (bin == B_FREE );
1575
- return null ;
1576
- }
1577
- }
1562
+ return pool.findBase(p);
1578
1563
return null ;
1579
1564
}
1580
1565
@@ -1735,8 +1720,11 @@ struct Gcx
1735
1720
// Return next item from free list
1736
1721
bucket[bin] = (cast (List* )p).next;
1737
1722
auto pool = (cast (List* )p).pool;
1723
+ auto biti = (p - pool.baseAddr) >> pool.shiftBy;
1724
+ assert (pool.freebits.test(biti));
1725
+ pool.freebits.clear(biti);
1738
1726
if (bits)
1739
- pool.setBits((p - pool.baseAddr) >> pool.shiftBy , bits);
1727
+ pool.setBits(biti , bits);
1740
1728
// debug(PRINTF) printf("\tmalloc => %p\n", p);
1741
1729
debug (MEMSTOMP ) memset(p, 0xF0 , alloc_size);
1742
1730
return p;
@@ -2141,38 +2129,15 @@ struct Gcx
2141
2129
// collection step 1: prepare freebits and mark bits
2142
2130
void prepare () nothrow
2143
2131
{
2144
- size_t n;
2145
- Pool* pool;
2146
-
2147
- for (n = 0 ; n < npools; n++ )
2148
- {
2149
- pool = pooltable[n];
2150
- pool.mark.zero();
2151
- if (! pool.isLargeObject) pool.freebits.zero();
2152
- }
2153
-
2154
- debug (COLLECT_PRINTF ) printf(" Set bits\n " );
2155
-
2156
- // Mark each free entry, so it doesn't get scanned
2157
- for (n = 0 ; n < B_PAGE ; n++ )
2158
- {
2159
- for (List * list = bucket[n]; list; list = list.next)
2160
- {
2161
- pool = list.pool;
2162
- assert (pool);
2163
- pool.freebits.set(cast (size_t )(cast (void * )list - pool.baseAddr) / 16 );
2164
- }
2165
- }
2132
+ debug (COLLECT_PRINTF ) printf(" preparing mark.\n " );
2166
2133
2167
- debug (COLLECT_PRINTF ) printf(" Marked free entries.\n " );
2168
-
2169
- for (n = 0 ; n < npools; n++ )
2134
+ for (size_t n = 0 ; n < npools; n++ )
2170
2135
{
2171
- pool = pooltable[n];
2172
- if (! pool.isLargeObject)
2173
- {
2136
+ Pool* pool = pooltable[n];
2137
+ if (pool.isLargeObject)
2138
+ pool.mark.zero();
2139
+ else
2174
2140
pool.mark.copy(&pool.freebits);
2175
- }
2176
2141
}
2177
2142
}
2178
2143
@@ -2488,7 +2453,7 @@ struct Gcx
2488
2453
* Returns true if the addr lies within a marked block.
2489
2454
*
2490
2455
* Warning! This should only be called while the world is stopped inside
2491
- * the fullcollect function.
2456
+ * the fullcollect function after all live objects have been marked, but before sweeping .
2492
2457
*/
2493
2458
int isMarked (void * addr) scope nothrow
2494
2459
{
@@ -2504,6 +2469,8 @@ struct Gcx
2504
2469
if (bins < B_PAGE )
2505
2470
{
2506
2471
biti = baseOffset(offset, bins) >> pool.ShiftBy.Small;
2472
+ // doesn't need to check freebits because no pointer must exist
2473
+ // to a block that was free before starting the collection
2507
2474
}
2508
2475
else if (bins == B_PAGE )
2509
2476
{
@@ -2719,6 +2686,7 @@ struct Pool
2719
2686
if (! isLargeObject)
2720
2687
{
2721
2688
freebits.alloc(nbits);
2689
+ freebits.setRange(0 , nbits);
2722
2690
}
2723
2691
2724
2692
noscan.alloc(nbits);
@@ -2949,6 +2917,38 @@ struct Pool
2949
2917
return (size + PAGESIZE - 1 ) / PAGESIZE ;
2950
2918
}
2951
2919
2920
+ void * findBase (void * p) nothrow @nogc
2921
+ {
2922
+ size_t offset = cast (size_t )(p - baseAddr);
2923
+ size_t pn = offset / PAGESIZE ;
2924
+ Bins bin = cast (Bins)pagetable[pn];
2925
+
2926
+ // Adjust bit to be at start of allocated memory block
2927
+ if (bin < B_NUMSMALL )
2928
+ {
2929
+ auto baseOff = baseOffset(offset, bin);
2930
+ const biti = baseOff >> Pool.ShiftBy.Small;
2931
+ if (freebits.test (biti))
2932
+ return null ;
2933
+ return baseAddr + baseOff;
2934
+ }
2935
+ if (bin == B_PAGE )
2936
+ {
2937
+ return baseAddr + (offset & (offset.max ^ (PAGESIZE - 1 )));
2938
+ }
2939
+ if (bin == B_PAGEPLUS )
2940
+ {
2941
+ size_t pageOffset = bPageOffsets[pn];
2942
+ offset -= pageOffset * PAGESIZE ;
2943
+ pn -= pageOffset;
2944
+
2945
+ return baseAddr + (offset & (offset.max ^ (PAGESIZE - 1 )));
2946
+ }
2947
+ // we are in a B_FREE page
2948
+ assert (bin == B_FREE );
2949
+ return null ;
2950
+ }
2951
+
2952
2952
size_t slGetSize (void * p) nothrow @nogc
2953
2953
{
2954
2954
if (isLargeObject)
@@ -3098,7 +3098,8 @@ struct LargeObjectPool
3098
3098
return 0 ;
3099
3099
size_t pagenum = pagenumOf(p);
3100
3100
Bins bin = cast (Bins)pagetable[pagenum];
3101
- assert (bin == B_PAGE );
3101
+ if (bin != B_PAGE )
3102
+ return 0 ;
3102
3103
return bPageOffsets[pagenum];
3103
3104
}
3104
3105
@@ -3194,6 +3195,9 @@ struct SmallObjectPool
3194
3195
assert (bin < B_PAGE );
3195
3196
if (p != cast (void * )baseOffset(cast (size_t )p, bin)) // check for interior pointer
3196
3197
return 0 ;
3198
+ const biti = cast (size_t )(p - baseAddr) >> ShiftBy.Small;
3199
+ if (freebits.test (biti))
3200
+ return 0 ;
3197
3201
return binsize[bin];
3198
3202
}
3199
3203
@@ -3207,10 +3211,15 @@ struct SmallObjectPool
3207
3211
if (bin >= B_PAGE )
3208
3212
return info;
3209
3213
3210
- info.base = cast (void * )baseOffset(cast (size_t )p, bin);
3214
+ auto base = cast (void * )baseOffset(cast (size_t )p, bin);
3215
+ const biti = cast (size_t )(base - baseAddr) >> ShiftBy.Small;
3216
+ if (freebits.test (biti))
3217
+ return info;
3218
+
3219
+ info.base = base;
3211
3220
info.size = binsize[bin];
3212
3221
offset = info.base - baseAddr;
3213
- info.attr = getBits(cast ( size_t )(offset >> ShiftBy.Small) );
3222
+ info.attr = getBits(biti );
3214
3223
3215
3224
return info;
3216
3225
}
@@ -3548,3 +3557,29 @@ version (D_LP64) unittest
3548
3557
}
3549
3558
}
3550
3559
}
3560
+
3561
+ // https://issues.dlang.org/show_bug.cgi?id=19522
3562
+ unittest
3563
+ {
3564
+ import core.memory ;
3565
+
3566
+ void test (void * p)
3567
+ {
3568
+ assert (GC .getAttr(p) == BlkAttr.NO_SCAN );
3569
+ assert (GC .setAttr(p + 4 , BlkAttr.NO_SCAN ) == 0 ); // interior pointer should fail
3570
+ assert (GC .clrAttr(p + 4 , BlkAttr.NO_SCAN ) == 0 ); // interior pointer should fail
3571
+ GC .free(p);
3572
+ assert (GC .query(p).base == null );
3573
+ assert (GC .query(p).size == 0 );
3574
+ assert (GC .addrOf(p) == null );
3575
+ assert (GC .sizeOf(p) == 0 ); // fails
3576
+ assert (GC .getAttr(p) == 0 );
3577
+ assert (GC .setAttr(p, BlkAttr.NO_SCAN ) == 0 );
3578
+ assert (GC .clrAttr(p, BlkAttr.NO_SCAN ) == 0 );
3579
+ }
3580
+ void * large = GC .malloc(10000 , BlkAttr.NO_SCAN );
3581
+ test(large);
3582
+
3583
+ void * small = GC .malloc(100 , BlkAttr.NO_SCAN );
3584
+ test(small);
3585
+ }
0 commit comments