am 35cff760
: Merge "Test that relro sharing actually saves memory."
* commit '35cff760dfc5d9d1432955503ffff02286ac20ef': Test that relro sharing actually saves memory.
This commit is contained in:
commit
551466e778
@ -252,8 +252,12 @@ bionic-unit-tests_ldflags := \
|
|||||||
-Wl,--export-dynamic \
|
-Wl,--export-dynamic \
|
||||||
-Wl,-u,DlSymTestFunction \
|
-Wl,-u,DlSymTestFunction \
|
||||||
|
|
||||||
|
bionic-unit-tests_c_includes := \
|
||||||
|
$(call include-path-for, libpagemap) \
|
||||||
|
|
||||||
bionic-unit-tests_shared_libraries_target := \
|
bionic-unit-tests_shared_libraries_target := \
|
||||||
libdl \
|
libdl \
|
||||||
|
libpagemap \
|
||||||
|
|
||||||
module := bionic-unit-tests
|
module := bionic-unit-tests
|
||||||
module_tag := optional
|
module_tag := optional
|
||||||
|
@ -24,8 +24,11 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <android/dlext.h>
|
#include <android/dlext.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <pagemap/pagemap.h>
|
||||||
|
|
||||||
|
|
||||||
#define ASSERT_DL_NOTNULL(ptr) \
|
#define ASSERT_DL_NOTNULL(ptr) \
|
||||||
ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror()
|
ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror()
|
||||||
@ -209,6 +212,8 @@ protected:
|
|||||||
EXPECT_EQ(4, f());
|
EXPECT_EQ(4, f());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
|
||||||
|
|
||||||
android_dlextinfo extinfo_;
|
android_dlextinfo extinfo_;
|
||||||
char relro_file_[PATH_MAX];
|
char relro_file_[PATH_MAX];
|
||||||
};
|
};
|
||||||
@ -230,3 +235,121 @@ TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
|
|||||||
|
|
||||||
ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
|
ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
|
||||||
|
int relro_fd = open(relro_file_, O_RDONLY);
|
||||||
|
ASSERT_NOERROR(relro_fd);
|
||||||
|
extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
|
||||||
|
extinfo_.relro_fd = relro_fd;
|
||||||
|
int pipefd[2];
|
||||||
|
ASSERT_NOERROR(pipe(pipefd));
|
||||||
|
|
||||||
|
size_t without_sharing, with_sharing;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing));
|
||||||
|
|
||||||
|
// We expect the sharing to save at least 10% of the total PSS. In practice
|
||||||
|
// it saves 40%+ for this test.
|
||||||
|
size_t expected_size = without_sharing - (without_sharing/10);
|
||||||
|
EXPECT_LT(with_sharing, expected_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getPss(pid_t pid, size_t* pss_out) {
|
||||||
|
pm_kernel_t* kernel;
|
||||||
|
ASSERT_EQ(0, pm_kernel_create(&kernel));
|
||||||
|
|
||||||
|
pm_process_t* process;
|
||||||
|
ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
|
||||||
|
|
||||||
|
pm_map_t** maps;
|
||||||
|
size_t num_maps;
|
||||||
|
ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
|
||||||
|
|
||||||
|
size_t total_pss = 0;
|
||||||
|
for (size_t i = 0; i < num_maps; i++) {
|
||||||
|
pm_memusage_t usage;
|
||||||
|
ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
|
||||||
|
total_pss += usage.pss;
|
||||||
|
}
|
||||||
|
*pss_out = total_pss;
|
||||||
|
|
||||||
|
free(maps);
|
||||||
|
pm_process_destroy(process);
|
||||||
|
pm_kernel_destroy(kernel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
|
||||||
|
size_t* pss_out) {
|
||||||
|
const int CHILDREN = 20;
|
||||||
|
|
||||||
|
// Create children
|
||||||
|
pid_t childpid[CHILDREN];
|
||||||
|
int childpipe[CHILDREN];
|
||||||
|
for (int i=0; i<CHILDREN; ++i) {
|
||||||
|
char read_buf;
|
||||||
|
int child_done_pipe[2], parent_done_pipe[2];
|
||||||
|
ASSERT_NOERROR(pipe(child_done_pipe));
|
||||||
|
ASSERT_NOERROR(pipe(parent_done_pipe));
|
||||||
|
|
||||||
|
pid_t child = fork();
|
||||||
|
if (child == 0) {
|
||||||
|
// close the 'wrong' ends of the pipes in the child
|
||||||
|
close(child_done_pipe[0]);
|
||||||
|
close(parent_done_pipe[1]);
|
||||||
|
|
||||||
|
// open the library
|
||||||
|
void* handle;
|
||||||
|
if (share_relro) {
|
||||||
|
handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
|
||||||
|
} else {
|
||||||
|
handle = dlopen(lib, RTLD_NOW);
|
||||||
|
}
|
||||||
|
if (handle == NULL) {
|
||||||
|
fprintf(stderr, "in child: %s\n", dlerror());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// close write end of child_done_pipe to signal the parent that we're done.
|
||||||
|
close(child_done_pipe[1]);
|
||||||
|
|
||||||
|
// wait for the parent to close parent_done_pipe, then exit
|
||||||
|
read(parent_done_pipe[0], &read_buf, 1);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_NOERROR(child);
|
||||||
|
|
||||||
|
// close the 'wrong' ends of the pipes in the parent
|
||||||
|
close(child_done_pipe[1]);
|
||||||
|
close(parent_done_pipe[0]);
|
||||||
|
|
||||||
|
// wait for the child to be done
|
||||||
|
read(child_done_pipe[0], &read_buf, 1);
|
||||||
|
close(child_done_pipe[0]);
|
||||||
|
|
||||||
|
// save the child's pid and the parent_done_pipe
|
||||||
|
childpid[i] = child;
|
||||||
|
childpipe[i] = parent_done_pipe[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum the PSS of all the children
|
||||||
|
size_t total_pss = 0;
|
||||||
|
for (int i=0; i<CHILDREN; ++i) {
|
||||||
|
size_t child_pss;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(getPss(childpid[i], &child_pss));
|
||||||
|
total_pss += child_pss;
|
||||||
|
}
|
||||||
|
*pss_out = total_pss;
|
||||||
|
|
||||||
|
// Close pipes and wait for children to exit
|
||||||
|
for (int i=0; i<CHILDREN; ++i) {
|
||||||
|
ASSERT_NOERROR(close(childpipe[i]));
|
||||||
|
}
|
||||||
|
for (int i=0; i<CHILDREN; ++i) {
|
||||||
|
int status;
|
||||||
|
ASSERT_EQ(childpid[i], waitpid(childpid[i], &status, 0));
|
||||||
|
ASSERT_TRUE(WIFEXITED(status));
|
||||||
|
ASSERT_EQ(0, WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user