Skip to content
This repository was archived by the owner on May 21, 2019. It is now read-only.

Commit 5764cd9

Browse files
committed
Only scan global sections containing data in LSan on darwin
Summary: __DATA segments on Darwin contain a large number of separate sections, many of which cannot actually contain pointers, and contain const values or objc metadata. Not scanning sections which cannot contain pointers significantly improves performance. On a medium-sized (~4000 files) internal project, I saw a speedup of about 30% in standalone LSan's execution time (30% improvement in the time spent running LSan, not the total program time). Reviewers: kcc, kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35432 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308999 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 416f183 commit 5764cd9

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

lib/lsan/lsan_common_mac.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,25 @@ LoadedModule *GetLinker() { return nullptr; }
9292
// required on Darwin.
9393
void InitializePlatformSpecificModules() {}
9494

95+
// Sections which can't contain contain global pointers. This list errs on the
96+
// side of caution to avoid false positives, at the expense of performance.
97+
//
98+
// Other potentially safe sections include:
99+
// __all_image_info, __crash_info, __const, __got, __interpose, __objc_msg_break
100+
//
101+
// Sections which definitely cannot be included here are:
102+
// __objc_data, __objc_const, __data, __bss, __common, __thread_data,
103+
// __thread_bss, __thread_vars, __objc_opt_rw, __objc_opt_ptrs
104+
static const char *kSkippedSecNames[] = {
105+
"__cfstring", "__la_symbol_ptr", "__mod_init_func",
106+
"__mod_term_func", "__nl_symbol_ptr", "__objc_classlist",
107+
"__objc_classrefs", "__objc_imageinfo", "__objc_nlclslist",
108+
"__objc_protolist", "__objc_selrefs", "__objc_superrefs"};
109+
95110
// Scans global variables for heap pointers.
96111
void ProcessGlobalRegions(Frontier *frontier) {
112+
for (auto name : kSkippedSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName);
113+
97114
MemoryMappingLayout memory_mapping(false);
98115
InternalMmapVector<LoadedModule> modules(/*initial_capacity*/ 128);
99116
memory_mapping.DumpListOfModules(&modules);
@@ -107,6 +124,10 @@ void ProcessGlobalRegions(Frontier *frontier) {
107124
// Sections storing global variables are writable and non-executable
108125
if (range.executable || !range.writable) continue;
109126

127+
for (auto name : kSkippedSecNames) {
128+
if (!internal_strcmp(range.name, name)) continue;
129+
}
130+
110131
ScanGlobalRange(range.beg, range.end, frontier);
111132
}
112133
}

lib/sanitizer_common/sanitizer_common.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,10 @@ void LoadedModule::clear() {
183183
}
184184

185185
void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
186-
bool writable) {
186+
bool writable, const char *name) {
187187
void *mem = InternalAlloc(sizeof(AddressRange));
188-
AddressRange *r = new(mem) AddressRange(beg, end, executable, writable);
188+
AddressRange *r =
189+
new(mem) AddressRange(beg, end, executable, writable, name);
189190
ranges_.push_back(r);
190191
if (executable && end > max_executable_address_)
191192
max_executable_address_ = end;

lib/sanitizer_common/sanitizer_common.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ inline const char *ModuleArchToString(ModuleArch arch) {
624624
}
625625

626626
const uptr kModuleUUIDSize = 16;
627+
const uptr kMaxSegName = 16;
627628

628629
// Represents a binary loaded into virtual memory (e.g. this can be an
629630
// executable or a shared object).
@@ -642,7 +643,8 @@ class LoadedModule {
642643
void set(const char *module_name, uptr base_address, ModuleArch arch,
643644
u8 uuid[kModuleUUIDSize], bool instrumented);
644645
void clear();
645-
void addAddressRange(uptr beg, uptr end, bool executable, bool writable);
646+
void addAddressRange(uptr beg, uptr end, bool executable, bool writable,
647+
const char *name = nullptr);
646648
bool containsAddress(uptr address) const;
647649

648650
const char *full_name() const { return full_name_; }
@@ -658,13 +660,17 @@ class LoadedModule {
658660
uptr end;
659661
bool executable;
660662
bool writable;
663+
char name[kMaxSegName];
661664

662-
AddressRange(uptr beg, uptr end, bool executable, bool writable)
665+
AddressRange(uptr beg, uptr end, bool executable, bool writable,
666+
const char *name)
663667
: next(nullptr),
664668
beg(beg),
665669
end(end),
666670
executable(executable),
667-
writable(writable) {}
671+
writable(writable) {
672+
internal_strncpy(this->name, (name ? name : ""), ARRAY_SIZE(this->name));
673+
}
668674
};
669675

670676
const IntrusiveList<AddressRange> &ranges() const { return ranges_; }

lib/sanitizer_common/sanitizer_procmaps_mac.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace __sanitizer {
3838

3939
// Contains information used to iterate through sections.
4040
struct MemoryMappedSegmentData {
41+
char name[kMaxSegName];
4142
uptr nsects;
4243
char *current_load_cmd_addr;
4344
u32 lc_type;
@@ -53,7 +54,8 @@ static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data,
5354

5455
uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr;
5556
uptr sec_end = sec_start + sc->size;
56-
module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable);
57+
module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable,
58+
sc->sectname);
5759
}
5860

5961
void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
@@ -63,7 +65,8 @@ void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
6365
// it will confuse libignore, and because the extra granularity
6466
// of information is not needed by any sanitizers.
6567
if (!data_ || !data_->nsects || IsExecutable()) {
66-
module->addAddressRange(start, end, IsExecutable(), IsWritable());
68+
module->addAddressRange(start, end, IsExecutable(), IsWritable(),
69+
data_ ? data_->name : nullptr);
6770
return;
6871
}
6972

@@ -212,6 +215,8 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) {
212215
segment->data_->lc_type = kLCSegment;
213216
segment->data_->base_virt_addr = base_virt_addr;
214217
segment->data_->addr_mask = addr_mask;
218+
internal_strncpy(segment->data_->name, sc->segname,
219+
ARRAY_SIZE(segment->data_->name));
215220
}
216221

217222
// Return the initial protection.

0 commit comments

Comments
 (0)