@@ -76,15 +76,8 @@ static inline size_t class_index_for_kind(page_kind_t kind) {
7676class Page ;
7777class Segment ;
7878
79- static constexpr uint32_t CHUNK_MAGIC = 0xC47A110CU ;
8079static constexpr uint64_t XL_MAGIC = 0x584C4F43484B4559ULL ; // "XLOCHKEY"
8180
82- struct ChunkHeader {
83- Page *owner;
84- uint32_t slot;
85- uint32_t magic;
86- };
87-
8881struct XLHeader {
8982 uint64_t magic;
9083 size_t mapping_size;
@@ -170,7 +163,6 @@ class Page {
170163 void *base;
171164 page_kind_t size_class;
172165 size_t page_span;
173- size_t chunk_stride;
174166 size_t chunk_usable;
175167 uint32_t capacity;
176168 uint32_t used;
@@ -181,17 +173,27 @@ class Page {
181173 std::vector<uint64_t > used_bitmap;
182174 DeferredRing deferred_frees;
183175
184- ChunkHeader * slot_header (uint32_t slot) const {
185- return reinterpret_cast <ChunkHeader *>(static_cast <char *>(base) +
186- static_cast <size_t >(slot) * chunk_stride );
176+ void * slot_ptr (uint32_t slot) const {
177+ return static_cast < void *>(static_cast <char *>(base) +
178+ static_cast <size_t >(slot) * chunk_usable );
187179 }
188180
189- void *slot_user_ptr (uint32_t slot) const {
190- return static_cast <void *>(reinterpret_cast <char *>(slot_header (slot)) + sizeof (ChunkHeader));
191- }
181+ bool ptr_to_slot_idx (void *ptr, uint32_t *slot_out) const {
182+ if (!initialized || !ptr || !slot_out || chunk_usable == 0 )
183+ return false ;
184+ const uintptr_t p = reinterpret_cast <uintptr_t >(ptr);
185+ const uintptr_t b = reinterpret_cast <uintptr_t >(base);
192186
193- ChunkHeader *user_to_header (void *ptr) const {
194- return reinterpret_cast <ChunkHeader *>(static_cast <char *>(ptr) - sizeof (ChunkHeader));
187+ PTR_IN_BOUNDS (b < p, " Chunk pointer points before owning page..." ); // if(p < b) => bad bad bad
188+
189+ const size_t offset = static_cast <size_t >(p - b);
190+ if ((offset % chunk_usable) != 0 ) // should be aligned at this point
191+ return false ;
192+ const size_t slot = offset / chunk_usable;
193+ if (slot >= capacity)
194+ return false ;
195+ *slot_out = static_cast <uint32_t >(slot);
196+ return true ;
195197 }
196198
197199 bool bit_is_set (uint32_t idx) const {
@@ -212,17 +214,6 @@ class Page {
212214 used_bitmap[word] &= ~(1ULL << bit);
213215 }
214216
215- bool validate_header (void *ptr, ChunkHeader *hdr) const {
216- if (!hdr)
217- return false ;
218- if (hdr->magic != CHUNK_MAGIC)
219- return false ;
220- if (hdr->owner != this )
221- return false ;
222- if (hdr->slot >= capacity)
223- return false ;
224- return slot_user_ptr (hdr->slot ) == ptr;
225- }
226217
227218 void drain_deferred_locked (size_t max_to_drain) {
228219 size_t drained = 0 ;
@@ -238,7 +229,7 @@ class Page {
238229public:
239230 Page ()
240231 : owner_segment(nullptr ), owner_segment_idx(0 ), base(nullptr ), size_class(PAGE_SM),
241- page_span (0 ), chunk_stride( 0 ), chunk_usable(0 ), capacity(0 ), used(0 ),
232+ page_span (0 ), chunk_usable(0 ), capacity(0 ), used(0 ),
242233 first_hint(0 ), owner_tid(0 ), status(EMPTY), initialized(false ), used_bitmap(),
243234 deferred_frees() {}
244235
@@ -252,21 +243,17 @@ class Page {
252243 return false ;
253244
254245 const size_t span = page_size_for_kind (kind);
255- size_t stride = 0 ;
256- size_t cap = 0 ;
257- const size_t norm_req = norm_chunk_req (kind, req_sz);
258- stride = align_up (norm_req + sizeof (ChunkHeader), 16 );
246+ const size_t stride = norm_chunk_req (kind, req_sz);
259247 if (stride == 0 )
260248 return false ;
261- cap = span / stride;
249+ const size_t cap = span / stride;
262250 if (cap == 0 || cap > UINT32_MAX)
263251 return false ;
264252
265253 base = page_base;
266254 size_class = kind;
267255 page_span = span;
268- chunk_stride = stride;
269- chunk_usable = stride - sizeof (ChunkHeader);
256+ chunk_usable = stride;
270257 capacity = static_cast <uint32_t >(cap);
271258 used = 0 ;
272259 first_hint = 0 ;
@@ -332,13 +319,8 @@ class Page {
332319 owner_tid = current_tid ();
333320 status = (used == capacity) ? FULL : ACTIVE;
334321
335- ChunkHeader *hdr = slot_header (slot);
336- hdr->owner = this ;
337- hdr->slot = slot;
338- hdr->magic = CHUNK_MAGIC;
339-
340322 *after = status;
341- return slot_user_ptr (slot);
323+ return slot_ptr (slot);
342324 }
343325 }
344326 word_idx = (word_idx + 1 ) % words;
@@ -355,14 +337,12 @@ class Page {
355337 page_status_t *after) {
356338 if (!contains_ptr (ptr))
357339 return false ;
358-
359- ChunkHeader *hdr = user_to_header (ptr);
360- if (!validate_header (ptr, hdr))
340+ uint32_t slot = 0 ;
341+ if (!ptr_to_slot_idx (ptr, &slot))
361342 return false ;
362343
363344 *before = status;
364- const uint32_t slot = hdr->slot ;
365- if (!bit_is_set (slot)) // double free detected. should probably make a macro for this.
345+ if (!bit_is_set (slot))
366346 std::abort ();
367347
368348 if (g_zero_on_free.load (std::memory_order_relaxed)) {
@@ -385,10 +365,11 @@ class Page {
385365 bool enqueue_deferred_free (void *ptr, size_t *usable_out) {
386366 if (!contains_ptr (ptr))
387367 return false ;
388-
389- ChunkHeader *hdr = user_to_header (ptr);
390- if (!validate_header (ptr, hdr))
368+ uint32_t slot = 0 ;
369+ if (!ptr_to_slot_idx (ptr, &slot))
391370 return false ;
371+ if (!bit_is_set (slot))
372+ std::abort ();
392373
393374 if (usable_out)
394375 *usable_out = chunk_usable;
@@ -398,13 +379,12 @@ class Page {
398379 size_t usable_size (void *ptr) const {
399380 if (!contains_ptr (ptr))
400381 return 0 ;
401-
402- ChunkHeader *hdr = user_to_header (ptr);
403- if (!validate_header (ptr, hdr))
382+ uint32_t slot = 0 ;
383+ if (!ptr_to_slot_idx (ptr, &slot))
404384 return 0 ;
405385
406386 if (g_uaf_check.load (std::memory_order_relaxed)) {
407- if (!bit_is_set (hdr-> slot ))
387+ if (!bit_is_set (slot))
408388 std::abort ();
409389 }
410390
@@ -478,6 +458,19 @@ class Segment {
478458 return p >= b && p < (b + SEGMENT_SIZE);
479459 }
480460
461+ bool resolve_page_for_ptr (void *ptr, Page **page_out) {
462+ if (!ptr || !page_out || !contains (ptr) || page_size == 0 )
463+ return false ;
464+ const uintptr_t b = reinterpret_cast <uintptr_t >(base);
465+ const uintptr_t p = reinterpret_cast <uintptr_t >(ptr);
466+ const size_t offset = static_cast <size_t >(p - b);
467+ const size_t idx = offset / page_size;
468+ if (idx >= page_count)
469+ return false ;
470+ *page_out = &pages[idx];
471+ return true ;
472+ }
473+
481474 bool has_free_pages () const {
482475 return full_pages.load (std::memory_order_relaxed) < page_count;
483476 }
@@ -781,6 +774,70 @@ class HeapState {
781774 return hdr->usable_size ;
782775 }
783776
777+ bool resolve_segment_for_ptr (void *ptr, size_t *seg_idx_out, Segment **seg_out) {
778+ if (!ptr || !seg_idx_out || !seg_out)
779+ return false ;
780+
781+ const uintptr_t p = reinterpret_cast <uintptr_t >(ptr);
782+ if (base && reserved_cursor > 0 ) {
783+ const uintptr_t b = reinterpret_cast <uintptr_t >(base);
784+ const uintptr_t end = b + reserved_cursor;
785+ if (p >= b && p < end) {
786+ const size_t idx = static_cast <size_t >((p - b) / SEGMENT_SIZE);
787+ if (idx < layout.size ()) {
788+ Segment *seg = layout[idx].get ();
789+ if (seg && seg->contains (ptr)) {
790+ *seg_idx_out = idx;
791+ *seg_out = seg;
792+ return true ;
793+ }
794+ }
795+ }
796+ }
797+ // TODO: still not sure if '~' is correct since i already subtract 1 from segment shift in type.h
798+ const uintptr_t seg_base = p & ~static_cast <uintptr_t >(SEGMENT_MASK);
799+ for (size_t i = 0 ; i < seg_bases.size (); ++i) {
800+ if (reinterpret_cast <uintptr_t >(seg_bases[i]) != seg_base)
801+ continue ;
802+ if (i >= layout.size ())
803+ continue ;
804+ Segment *seg = layout[i].get ();
805+ if (seg && seg->contains (ptr)) {
806+ *seg_idx_out = i;
807+ *seg_out = seg;
808+ return true ;
809+ }
810+ }
811+ // TODO: confirm neither this nor the above are necessary
812+ for (size_t i = 0 ; i < layout.size (); ++i) {
813+ Segment *seg = layout[i].get ();
814+ if (seg && seg->contains (ptr)) {
815+ *seg_idx_out = i;
816+ *seg_out = seg;
817+ return true ;
818+ }
819+ }
820+
821+ return false ;
822+ }
823+
824+ bool resolve_page_for_ptr (void *ptr, size_t *seg_idx_out, Segment **seg_out,
825+ Page **page_out) {
826+ if (!ptr || !seg_idx_out || !seg_out || !page_out)
827+ return false ;
828+ size_t seg_idx = 0 ;
829+ Segment *seg = nullptr ;
830+ if (!resolve_segment_for_ptr (ptr, &seg_idx, &seg))
831+ return false ;
832+ Page *page = nullptr ;
833+ if (!seg->resolve_page_for_ptr (ptr, &page))
834+ return false ;
835+ *seg_idx_out = seg_idx;
836+ *seg_out = seg;
837+ *page_out = page;
838+ return true ;
839+ }
840+
784841public:
785842 HeapState ()
786843 : base(nullptr ), reserved_size(0 ), num_segments(0 ), layout(),
@@ -827,9 +884,7 @@ class HeapState {
827884
828885 page_kind_t kind = class_for_size (size);
829886 if (kind == PAGE_XL) {
830- // goto xl path?
831- const size_t large_fit_limit = LARGE_PAGE_SIZE - sizeof (ChunkHeader);
832- if (size <= large_fit_limit) {
887+ if (size <= LARGE_PAGE_SIZE) {
833888 kind = PAGE_LG;
834889 } else {
835890 return alloc_xl (size);
@@ -972,15 +1027,10 @@ class HeapState {
9721027 return true ;
9731028
9741029 ThreadCache *tc = ThreadCache::current ();
975-
976- ChunkHeader *chdr = reinterpret_cast <ChunkHeader *>(
977- static_cast <char *>(ptr) - sizeof (ChunkHeader));
978- if (chdr->magic == CHUNK_MAGIC && chdr->owner ) {
979- Page *page = chdr->owner ;
980- Segment *seg = page->get_owner_segment ();
981- if (!seg)
982- return false ;
983-
1030+ size_t seg_idx = 0 ;
1031+ Segment *seg = nullptr ;
1032+ Page *page = nullptr ;
1033+ if (resolve_page_for_ptr (ptr, &seg_idx, &seg, &page)) {
9841034 const page_kind_t kind = page->get_size_class ();
9851035 const pid_t owner_tid = page->get_owner_tid ();
9861036 const bool remote_owner = (owner_tid != 0 && owner_tid != tc->get_tid ());
@@ -999,10 +1049,10 @@ class HeapState {
9991049 }
10001050
10011051 if (!ok)
1002- std::abort () ;
1052+ return false ;
10031053
10041054 if (!remote_owner && before == FULL && after != FULL) {
1005- enqueue_non_full_segment (kind, page-> get_segment_index () );
1055+ enqueue_non_full_segment (kind, seg_idx );
10061056 }
10071057
10081058 if (tc->get_active ()) {
@@ -1024,10 +1074,11 @@ class HeapState {
10241074 if (!ptr)
10251075 return 0 ;
10261076
1027- ChunkHeader *chdr = reinterpret_cast <ChunkHeader *>(
1028- static_cast <char *>(ptr) - sizeof (ChunkHeader));
1029- if (chdr->magic == CHUNK_MAGIC && chdr->owner )
1030- return chdr->owner ->usable_size (ptr);
1077+ size_t seg_idx = 0 ;
1078+ Segment *seg = nullptr ;
1079+ Page *page = nullptr ;
1080+ if (resolve_page_for_ptr (ptr, &seg_idx, &seg, &page))
1081+ return page->usable_size (ptr);
10311082
10321083 return usable_xl (ptr);
10331084 }
0 commit comments