Skip to content

Commit

Permalink
[sanitizer_common] Several Solaris procmaps fixes
Browse files Browse the repository at this point in the history
Since the introduction of GoogleTest sharding in D122251
<https://reviews.llvm.org/D122251>, some of the Solaris sanitizer tests
have been running extremly long (up to an hour) while they took mere
seconds before.  Initial investigation suggests that massive lock
contention in Solaris procfs is involved here.

However, there's an easy way to somewhat reduce the impact: while the
current `ReadProcMaps` uses `ReadFileToBuffer` to read `/proc/self/xmap`,
that function primarily caters to Linux procfs reporting file sizes of 0
while the size on Solaris is accurate.  This patch makes use of that,
reducing the number of syscalls involved and reducing the runtime of
affected tests by a factor of 4.

Besides, it handles shared mappings and doesn't call `readlink` for unnamed
map entries.

Tested on `sparcv9-sun-solaris2.11` and `amd64-pc-solaris2.11`.

Differential Revision: https://reviews.llvm.org/D129837
  • Loading branch information
rorth committed Jul 16, 2022
1 parent fe47cfb commit 74f6672
Showing 1 changed file with 36 additions and 22 deletions.
58 changes: 36 additions & 22 deletions compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,32 @@
// Information about the process mappings (Solaris-specific parts).
//===----------------------------------------------------------------------===//

// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
#undef _FILE_OFFSET_BITS
#include "sanitizer_platform.h"
#if SANITIZER_SOLARIS
#include "sanitizer_common.h"
#include "sanitizer_procmaps.h"
# include <fcntl.h>
# include <limits.h>
# include <procfs.h>

#include <procfs.h>
#include <limits.h>
# include "sanitizer_common.h"
# include "sanitizer_procmaps.h"

namespace __sanitizer {

void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
if (!ReadFileToBuffer("/proc/self/xmap", &proc_maps->data,
&proc_maps->mmaped_size, &proc_maps->len)) {
proc_maps->data = nullptr;
proc_maps->mmaped_size = 0;
proc_maps->len = 0;
}
uptr fd = internal_open("/proc/self/xmap", O_RDONLY);
CHECK_NE(fd, -1);
uptr Size = internal_filesize(fd);
CHECK_GT(Size, 0);

// Allow for additional entries by following mmap.
size_t MmapedSize = Size * 4 / 3;
void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
Size = internal_read(fd, VmMap, MmapedSize);
CHECK_NE(Size, -1);
internal_close(fd);
proc_maps->data = (char *)VmMap;
proc_maps->mmaped_size = MmapedSize;
proc_maps->len = Size;
}

bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
Expand All @@ -49,21 +56,28 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
segment->protection |= kProtectionWrite;
if ((xmapentry->pr_mflags & MA_EXEC) != 0)
segment->protection |= kProtectionExecute;
if ((xmapentry->pr_mflags & MA_SHARED) != 0)
segment->protection |= kProtectionShared;

if (segment->filename != NULL && segment->filename_size > 0) {
char proc_path[PATH_MAX + 1];

internal_snprintf(proc_path, sizeof(proc_path), "/proc/self/path/%s",
xmapentry->pr_mapname);
ssize_t sz = internal_readlink(proc_path, segment->filename,
segment->filename_size - 1);

// If readlink failed, the map is anonymous.
if (sz == -1) {
// Avoid unnecessary readlink on unnamed entires.
if (xmapentry->pr_mapname[0] == '\0')
segment->filename[0] = '\0';
} else if ((size_t)sz < segment->filename_size)
// readlink doesn't NUL-terminate.
segment->filename[sz] = '\0';
else {
internal_snprintf(proc_path, sizeof(proc_path), "/proc/self/path/%s",
xmapentry->pr_mapname);
ssize_t sz = internal_readlink(proc_path, segment->filename,
segment->filename_size - 1);

// If readlink failed, the map is anonymous.
if (sz == -1)
segment->filename[0] = '\0';
else if ((size_t)sz < segment->filename_size)
// readlink doesn't NUL-terminate.
segment->filename[sz] = '\0';
}
}

data_.current += sizeof(prxmap_t);
Expand Down

0 comments on commit 74f6672

Please sign in to comment.