Skip to content

Commit 4f9dabd

Browse files
authored
Merge pull request #238 from struct/arm_native_sanity_checks
optionally use arm intrinsics to debug functions
2 parents 6599811 + 7021c1e commit 4f9dabd

2 files changed

Lines changed: 62 additions & 37 deletions

File tree

src/iso_alloc_profiler.c

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -125,41 +125,50 @@ INTERNAL_HIDDEN uint64_t _iso_alloc_zone_leak_detector(iso_alloc_zone_t *zone, b
125125
uint32_t was_used = 0;
126126
int64_t bms = zone->bitmap_size / sizeof(bitmap_index_t);
127127

128-
for(bitmap_index_t i = 0; i < bms; i++) {
129-
for(int j = 0; j < BITS_PER_QWORD; j += BITS_PER_CHUNK) {
130-
131-
if(bm[i] == 0) {
128+
for(int64_t i = 0; i < bms;) {
129+
#if USE_NEON
130+
/* Two-qword quick-reject: load 16 bytes of bitmap and skip both
131+
* qwords when every chunk in those 64 slots is free and never used. */
132+
if(i + 1 < bms) {
133+
int64x2_t v = vld1q_s64((const int64_t *) &bm[i]);
134+
if((vgetq_lane_s64(v, 0) | vgetq_lane_s64(v, 1)) == 0) {
135+
i += 2;
132136
continue;
133137
}
138+
}
139+
#endif
140+
uint64_t bts = (uint64_t) bm[i];
141+
if(bts == 0) {
142+
i++;
143+
continue;
144+
}
134145

135-
int64_t bit = GET_BIT(bm[i], j);
136-
int64_t bit_two = GET_BIT(bm[i], (j + 1));
146+
/* was_used (encoding 01: low=0, high=1) — popcount the odd-bit
147+
* positions whose paired even bit is clear. */
148+
was_used += __builtin_popcountll((~bts) & (bts >> 1) & USED_BIT_VECTOR);
137149

138-
/* Chunk was used but is now free */
139-
if(bit == 0 && bit_two == 1) {
140-
was_used++;
141-
}
150+
/* Chunks with low bit set are either in-use (10) or canary (11).
151+
* Walk just those positions with ctz instead of testing all 32. */
152+
uint64_t in_use_low = bts & USED_BIT_VECTOR;
153+
while(in_use_low) {
154+
int j = __builtin_ctzll(in_use_low);
155+
in_use_low &= in_use_low - 1;
156+
157+
int64_t bit_two = GET_BIT(bts, (j + 1));
158+
bit_slot_t bit_slot = ((bitmap_index_t) i * BITS_PER_QWORD) + j;
159+
const void *leak = (zone->user_pages_start + ((bit_slot >> 1) * zone->chunk_size));
160+
161+
if(bit_two == 1 && (check_canary_no_abort(zone, leak) != ERR)) {
162+
continue;
163+
} else {
164+
in_use++;
142165

143-
if(bit == 1) {
144-
/* Theres no difference between a leaked and previously
145-
* used chunk (11) and a canary chunk (11). So in order
146-
* to accurately report on leaks we need to verify the
147-
* canary value. If it doesn't validate then we assume
148-
* its a true leak and increment the in_use counter */
149-
bit_slot_t bit_slot = (i * BITS_PER_QWORD) + j;
150-
const void *leak = (zone->user_pages_start + ((bit_slot >> 1) * zone->chunk_size));
151-
152-
if(bit_two == 1 && (check_canary_no_abort(zone, leak) != ERR)) {
153-
continue;
154-
} else {
155-
in_use++;
156-
157-
if(profile == false) {
158-
LOG("Leaked chunk (%d) in zone[%d] of %d bytes detected at 0x%p (bit position = %d)", in_use, zone->index, zone->chunk_size, leak, bit_slot);
159-
}
166+
if(profile == false) {
167+
LOG("Leaked chunk (%d) in zone[%d] of %d bytes detected at 0x%p (bit position = %d)", in_use, zone->index, zone->chunk_size, leak, bit_slot);
160168
}
161169
}
162170
}
171+
i++;
163172
}
164173

165174
if(profile == false) {

src/iso_alloc_sanity.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,34 @@ INTERNAL_HIDDEN void _verify_zone(iso_alloc_zone_t *zone) {
103103
}
104104
}
105105

106-
for(bitmap_index_t i = 0; i < zone->max_bitmap_idx; i++) {
107-
bit_slot_t bsl = bm[i];
108-
for(int64_t j = 1; j < BITS_PER_QWORD; j += BITS_PER_CHUNK) {
109-
/* If this bit is set it is either a free chunk or
110-
* a canary chunk. Either way it should have a set
111-
* of canaries we can verify */
112-
if((GET_BIT(bsl, j)) == 1) {
113-
bit_slot = (i << BITS_PER_QWORD_SHIFT) + j;
114-
const void *p = POINTER_FROM_BITSLOT(zone, bit_slot);
115-
check_canary(zone, p);
106+
/* A chunk needs canary verification when the high bit of its 2-bit
107+
* slot is set (was-used-now-free=01 or canary=11) — the odd-bit mask. */
108+
const uint64_t CANARY_BIT_VECTOR = ~(uint64_t) USED_BIT_VECTOR;
109+
const bitmap_index_t max = zone->max_bitmap_idx;
110+
111+
for(bitmap_index_t i = 0; i < max;) {
112+
#if USE_NEON
113+
/* Two-qword quick-reject: skip 64 chunk slots when none of them
114+
* have the high bit set (no canaries to verify in this range). */
115+
if(i + 1 < max) {
116+
int64x2_t v = vld1q_s64((const int64_t *) &bm[i]);
117+
uint64_t lo = (uint64_t) vgetq_lane_s64(v, 0);
118+
uint64_t hi = (uint64_t) vgetq_lane_s64(v, 1);
119+
if(((lo | hi) & CANARY_BIT_VECTOR) == 0) {
120+
i += 2;
121+
continue;
116122
}
117123
}
124+
#endif
125+
uint64_t mask = (uint64_t) bm[i] & CANARY_BIT_VECTOR;
126+
while(mask) {
127+
int j = __builtin_ctzll(mask);
128+
mask &= mask - 1;
129+
bit_slot = ((bit_slot_t) i << BITS_PER_QWORD_SHIFT) + j;
130+
const void *p = POINTER_FROM_BITSLOT(zone, bit_slot);
131+
check_canary(zone, p);
132+
}
133+
i++;
118134
}
119135

120136
MASK_ZONE_PTRS(zone);

0 commit comments

Comments
 (0)