@@ -45,7 +45,6 @@ struct MemoryMappedSegmentData {
4545 const char *current_load_cmd_addr;
4646 u32 lc_type;
4747 uptr base_virt_addr;
48- uptr addr_mask;
4948};
5049
5150template <typename Section>
@@ -54,12 +53,58 @@ static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data,
5453 const Section *sc = (const Section *)data->current_load_cmd_addr ;
5554 data->current_load_cmd_addr += sizeof (Section);
5655
57- uptr sec_start = ( sc->addr & data-> addr_mask ) + data->base_virt_addr ;
56+ uptr sec_start = sc->addr + data->base_virt_addr ;
5857 uptr sec_end = sec_start + sc->size ;
5958 module ->addAddressRange (sec_start, sec_end, /* executable=*/ false , isWritable,
6059 sc->sectname );
6160}
6261
62+ static bool VerifyMemoryMapping (MemoryMappingLayout* mapping) {
63+ InternalMmapVector<LoadedModule> modules;
64+ modules.reserve (128 ); // matches DumpProcessMap
65+ mapping->DumpListOfModules (&modules);
66+
67+ InternalMmapVector<LoadedModule::AddressRange> segments;
68+ for (uptr i = 0 ; i < modules.size (); ++i) {
69+ for (auto & range : modules[i].ranges ()) {
70+ segments.push_back (range);
71+ }
72+ }
73+
74+ // Verify that none of the segments overlap:
75+ // 1. Sort the segments by the start address
76+ // 2. Check that every segment starts after the previous one ends.
77+ Sort (segments.data (), segments.size (),
78+ [](LoadedModule::AddressRange& a, LoadedModule::AddressRange& b) {
79+ return a.beg < b.beg ;
80+ });
81+
82+ // To avoid spam, we only print the report message once-per-process.
83+ static bool invalid_module_map_reported = false ;
84+ bool well_formed = true ;
85+
86+ for (size_t i = 1 ; i < segments.size (); i++) {
87+ uptr cur_start = segments[i].beg ;
88+ uptr prev_end = segments[i - 1 ].end ;
89+ if (cur_start < prev_end) {
90+ well_formed = false ;
91+ VReport (2 , " Overlapping mappings: %s start = %p, %s end = %p\n " ,
92+ segments[i].name , (void *)cur_start, segments[i - 1 ].name ,
93+ (void *)prev_end);
94+ if (!invalid_module_map_reported) {
95+ Report (
96+ " WARN: Invalid dyld module map detected. This is most likely a bug "
97+ " in the sanitizer.\n " );
98+ Report (" WARN: Backtraces may be unreliable.\n " );
99+ invalid_module_map_reported = true ;
100+ }
101+ }
102+ }
103+
104+ mapping->Reset ();
105+ return well_formed;
106+ }
107+
63108void MemoryMappedSegment::AddAddressRanges (LoadedModule *module ) {
64109 // Don't iterate over sections when the caller hasn't set up the
65110 // data pointer, when there are no sections, or when the segment
@@ -85,6 +130,7 @@ void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
85130
86131MemoryMappingLayout::MemoryMappingLayout (bool cache_enabled) {
87132 Reset ();
133+ VerifyMemoryMapping (this );
88134}
89135
90136MemoryMappingLayout::~MemoryMappingLayout () {
@@ -190,6 +236,7 @@ typedef struct dyld_shared_cache_dylib_text_info
190236
191237extern bool _dyld_get_shared_cache_uuid (uuid_t uuid);
192238extern const void *_dyld_get_shared_cache_range (size_t *length);
239+ extern intptr_t _dyld_get_image_slide (const struct mach_header * mh);
193240extern int dyld_shared_cache_iterate_text (
194241 const uuid_t cacheUuid,
195242 void (^callback)(const dyld_shared_cache_dylib_text_info *info));
@@ -258,23 +305,21 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment,
258305 layout_data->current_load_cmd_count --;
259306 if (((const load_command *)lc)->cmd == kLCSegment ) {
260307 const SegmentCommand* sc = (const SegmentCommand *)lc;
261- uptr base_virt_addr, addr_mask;
262- if (layout_data-> current_image == kDyldImageIdx ) {
263- base_virt_addr = (uptr) get_dyld_hdr ();
264- // vmaddr is masked with 0xfffff because on macOS versions < 10.12,
265- // it contains an absolute address rather than an offset for dyld.
266- // To make matters even more complicated, this absolute address
267- // isn't actually the absolute segment address, but the offset portion
268- // of the address is accurate when combined with the dyld base address,
269- // and the mask will give just this offset.
270- addr_mask = 0xfffff ;
271- } else {
308+ if ( strncmp (sc-> segname , " __LINKEDIT " , sizeof ( " __LINKEDIT " )) == 0 ) {
309+ // The LINKEDIT sections are for internal linker use, and may alias
310+ // with the LINKEDIT section for other modules. (If we included them,
311+ // our memory map would contain overlappping sections.)
312+ return false ;
313+ }
314+
315+ uptr base_virt_addr;
316+ if (layout_data-> current_image == kDyldImageIdx )
317+ base_virt_addr = (uptr) _dyld_get_image_slide ( get_dyld_hdr ()) ;
318+ else
272319 base_virt_addr =
273320 (uptr)_dyld_get_image_vmaddr_slide (layout_data->current_image );
274- addr_mask = ~0 ;
275- }
276321
277- segment->start = ( sc->vmaddr & addr_mask) + base_virt_addr;
322+ segment->start = sc->vmaddr + base_virt_addr;
278323 segment->end = segment->start + sc->vmsize ;
279324 // Most callers don't need section information, so only fill this struct
280325 // when required.
@@ -284,7 +329,6 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment,
284329 (const char *)lc + sizeof (SegmentCommand);
285330 seg_data->lc_type = kLCSegment ;
286331 seg_data->base_virt_addr = base_virt_addr;
287- seg_data->addr_mask = addr_mask;
288332 internal_strncpy (seg_data->name , sc->segname ,
289333 ARRAY_SIZE (seg_data->name ));
290334 }
0 commit comments