Skip to content

Commit d81723c

Browse files
committed
[DFSan] Optimize code for writing to shadow. Move SetShadow to namespace.
Writing zeros to shadow (including checking for existing zero) is now ~2x faster on one example. Reviewed By: morehouse Differential Revision: https://reviews.llvm.org/D110733
1 parent 0337e22 commit d81723c

File tree

1 file changed

+38
-54
lines changed

1 file changed

+38
-54
lines changed

compiler-rt/lib/dfsan/dfsan.cpp

Lines changed: 38 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -369,37 +369,6 @@ static void SetOrigin(const void *dst, uptr size, u32 origin) {
369369
*(u32 *)(end - kOriginAlign) = origin;
370370
}
371371

372-
static void WriteShadowInRange(dfsan_label label, uptr beg_shadow_addr,
373-
uptr end_shadow_addr) {
374-
// TODO: After changing dfsan_label to 8bit, use internal_memset when label
375-
// is not 0.
376-
dfsan_label *labelp = (dfsan_label *)beg_shadow_addr;
377-
if (label) {
378-
for (; (uptr)labelp < end_shadow_addr; ++labelp) *labelp = label;
379-
return;
380-
}
381-
382-
for (; (uptr)labelp < end_shadow_addr; ++labelp) {
383-
// Don't write the label if it is already the value we need it to be.
384-
// In a program where most addresses are not labeled, it is common that
385-
// a page of shadow memory is entirely zeroed. The Linux copy-on-write
386-
// implementation will share all of the zeroed pages, making a copy of a
387-
// page when any value is written. The un-sharing will happen even if
388-
// the value written does not change the value in memory. Avoiding the
389-
// write when both |label| and |*labelp| are zero dramatically reduces
390-
// the amount of real memory used by large programs.
391-
if (!*labelp)
392-
continue;
393-
394-
*labelp = 0;
395-
}
396-
}
397-
398-
static void WriteShadowWithSize(dfsan_label label, uptr shadow_addr,
399-
uptr size) {
400-
WriteShadowInRange(label, shadow_addr, shadow_addr + size * sizeof(label));
401-
}
402-
403372
#define RET_CHAIN_ORIGIN(id) \
404373
GET_CALLER_PC_BP_SP; \
405374
(void)sp; \
@@ -451,21 +420,6 @@ void dfsan_copy_memory(void *dst, const void *src, uptr size) {
451420
dfsan_mem_origin_transfer(dst, src, size);
452421
}
453422

454-
} // namespace __dfsan
455-
456-
// If the label s is tainted, set the size bytes from the address p to be a new
457-
// origin chain with the previous ID o and the current stack trace. This is
458-
// used by instrumentation to reduce code size when too much code is inserted.
459-
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin(
460-
dfsan_label s, void *p, uptr size, dfsan_origin o) {
461-
if (UNLIKELY(s)) {
462-
GET_CALLER_PC_BP_SP;
463-
(void)sp;
464-
GET_STORE_STACK_TRACE_PC_BP(pc, bp);
465-
SetOrigin(p, size, ChainOrigin(o, &stack));
466-
}
467-
}
468-
469423
// Releases the pages within the origin address range.
470424
static void ReleaseOrigins(void *addr, uptr size) {
471425
const uptr beg_origin_addr = (uptr)__dfsan::origin_for(addr);
@@ -484,6 +438,19 @@ static void ReleaseOrigins(void *addr, uptr size) {
484438
Die();
485439
}
486440

441+
static void WriteZeroShadowInRange(uptr beg, uptr end) {
442+
// Don't write the label if it is already the value we need it to be.
443+
// In a program where most addresses are not labeled, it is common that
444+
// a page of shadow memory is entirely zeroed. The Linux copy-on-write
445+
// implementation will share all of the zeroed pages, making a copy of a
446+
// page when any value is written. The un-sharing will happen even if
447+
// the value written does not change the value in memory. Avoiding the
448+
// write when both |label| and |*labelp| are zero dramatically reduces
449+
// the amount of real memory used by large programs.
450+
if (!mem_is_zero((const char *)beg, end - beg))
451+
internal_memset((void *)beg, 0, end - beg);
452+
}
453+
487454
// Releases the pages within the shadow address range, and sets
488455
// the shadow addresses not on the pages to be 0.
489456
static void ReleaseOrClearShadows(void *addr, uptr size) {
@@ -492,20 +459,22 @@ static void ReleaseOrClearShadows(void *addr, uptr size) {
492459
const uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr);
493460

494461
if (end_shadow_addr - beg_shadow_addr <
495-
common_flags()->clear_shadow_mmap_threshold)
496-
return WriteShadowWithSize(0, beg_shadow_addr, size);
462+
common_flags()->clear_shadow_mmap_threshold) {
463+
WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
464+
return;
465+
}
497466

498467
const uptr page_size = GetPageSizeCached();
499468
const uptr beg_aligned = RoundUpTo(beg_shadow_addr, page_size);
500469
const uptr end_aligned = RoundDownTo(end_shadow_addr, page_size);
501470

502471
if (beg_aligned >= end_aligned) {
503-
WriteShadowWithSize(0, beg_shadow_addr, size);
472+
WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
504473
} else {
505474
if (beg_aligned != beg_shadow_addr)
506-
WriteShadowInRange(0, beg_shadow_addr, beg_aligned);
475+
WriteZeroShadowInRange(beg_shadow_addr, beg_aligned);
507476
if (end_aligned != end_shadow_addr)
508-
WriteShadowInRange(0, end_aligned, end_shadow_addr);
477+
WriteZeroShadowInRange(end_aligned, end_shadow_addr);
509478
if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))
510479
Die();
511480
}
@@ -514,7 +483,7 @@ static void ReleaseOrClearShadows(void *addr, uptr size) {
514483
void SetShadow(dfsan_label label, void *addr, uptr size, dfsan_origin origin) {
515484
if (0 != label) {
516485
const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);
517-
WriteShadowWithSize(label, beg_shadow_addr, size);
486+
internal_memset((void *)beg_shadow_addr, label, size);
518487
if (dfsan_get_track_origins())
519488
SetOrigin(addr, size, origin);
520489
return;
@@ -526,9 +495,24 @@ void SetShadow(dfsan_label label, void *addr, uptr size, dfsan_origin origin) {
526495
ReleaseOrClearShadows(addr, size);
527496
}
528497

498+
} // namespace __dfsan
499+
500+
// If the label s is tainted, set the size bytes from the address p to be a new
501+
// origin chain with the previous ID o and the current stack trace. This is
502+
// used by instrumentation to reduce code size when too much code is inserted.
503+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin(
504+
dfsan_label s, void *p, uptr size, dfsan_origin o) {
505+
if (UNLIKELY(s)) {
506+
GET_CALLER_PC_BP_SP;
507+
(void)sp;
508+
GET_STORE_STACK_TRACE_PC_BP(pc, bp);
509+
SetOrigin(p, size, ChainOrigin(o, &stack));
510+
}
511+
}
512+
529513
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label(
530514
dfsan_label label, dfsan_origin origin, void *addr, uptr size) {
531-
SetShadow(label, addr, size, origin);
515+
__dfsan::SetShadow(label, addr, size, origin);
532516
}
533517

534518
SANITIZER_INTERFACE_ATTRIBUTE
@@ -539,7 +523,7 @@ void dfsan_set_label(dfsan_label label, void *addr, uptr size) {
539523
GET_STORE_STACK_TRACE_PC_BP(pc, bp);
540524
init_origin = ChainOrigin(0, &stack, true);
541525
}
542-
SetShadow(label, addr, size, init_origin);
526+
__dfsan::SetShadow(label, addr, size, init_origin);
543527
}
544528

545529
SANITIZER_INTERFACE_ATTRIBUTE

0 commit comments

Comments
 (0)