dlfcn_test.cpp revision 5419b9474753d25dff947c7740532f86d130c0be
1acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao/*
2acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Copyright (C) 2012 The Android Open Source Project
3acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
4acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Licensed under the Apache License, Version 2.0 (the "License");
5acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * you may not use this file except in compliance with the License.
6acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * You may obtain a copy of the License at
7acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
8acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *      http://www.apache.org/licenses/LICENSE-2.0
9acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
10acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Unless required by applicable law or agreed to in writing, software
11acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * distributed under the License is distributed on an "AS IS" BASIS,
12acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * See the License for the specific language governing permissions and
14acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * limitations under the License.
15acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao */
16acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
17acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <gtest/gtest.h>
18acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
19acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <dlfcn.h>
208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <libgen.h>
218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <limits.h>
228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdio.h>
238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdint.h>
248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string>
26acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
273b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
283b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
30acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaostatic bool gCalled = false;
31acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
32acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  gCalled = true;
33acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
34acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
35acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoTEST(dlopen, dlsym_in_self) {
363b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
37acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* self = dlopen(NULL, RTLD_NOW);
38acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(self != NULL);
393b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
40acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
41acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
42acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(sym != NULL);
43acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
44acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
45acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
46acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  gCalled = false;
47acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
48acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(gCalled);
49acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
508e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott HughesTEST(dlopen, dlopen_failure) {
523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self == NULL);
543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#if __BIONIC__
553b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
563b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
573b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
583b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
593b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
603b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
615419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic void* ConcurrentDlErrorFn(void* arg) {
625419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/child/thread", RTLD_NOW);
635419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return reinterpret_cast<void*>(strdup(dlerror()));
645419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
655419b9474753d25dff947c7740532f86d130c0beElliott Hughes
665419b9474753d25dff947c7740532f86d130c0beElliott HughesTEST(dlopen, dlerror_concurrent) {
675419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/main/thread", RTLD_NOW);
685419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
695419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
705419b9474753d25dff947c7740532f86d130c0beElliott Hughes
715419b9474753d25dff947c7740532f86d130c0beElliott Hughes  pthread_t t;
725419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
735419b9474753d25dff947c7740532f86d130c0beElliott Hughes  void* result;
745419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_join(t, &result));
755419b9474753d25dff947c7740532f86d130c0beElliott Hughes  char* child_thread_error = static_cast<char*>(result);
765419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/child/thread", child_thread_error);
775419b9474753d25dff947c7740532f86d130c0beElliott Hughes  free(child_thread_error);
785419b9474753d25dff947c7740532f86d130c0beElliott Hughes
795419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
805419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
815419b9474753d25dff947c7740532f86d130c0beElliott Hughes
823b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott HughesTEST(dlopen, dlsym_failures) {
833b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
843b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
853b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self != NULL);
863b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
873b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
883b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
893b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
903b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // NULL handle.
913b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(NULL, "test");
923b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
933b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#if __BIONIC__
943b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
953b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
963b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: test", dlerror()); // glibc isn't specific about the failure.
973b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
983b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
993b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // NULL symbol name.
1003b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#if __BIONIC__
1013b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // glibc marks this parameter non-null and SEGVs if you cheat.
1023b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, NULL);
1033b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
1043b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("", dlerror());
1053b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
1063b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1073b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
1083b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
1093b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
1103b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
1113b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
1123b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1138e15b08ae22a5230c1fea4779410de0420fa939cElliott HughesTEST(dlopen, dladdr) {
1143b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
1158e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
1168e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(self != NULL);
1173b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
1188e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
1208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(sym != NULL);
1218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
1238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
1248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
1268e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
1278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
1288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1298e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
1308e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char executable_path[PATH_MAX];
1318e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
1328e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, -1);
1338e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  executable_path[rc] = '\0';
1348e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string executable_name(basename(executable_path));
1358e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1368e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
1378e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
1388e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string dli_fname(info.dli_fname);
1398e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  dli_fname = basename(&dli_fname[0]);
1408e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dli_fname, executable_name);
1418e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1428e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
1438e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
1448e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1458e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
1468e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
1478e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1488e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Look in /proc/pid/maps to find out what address we were loaded at.
1498e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
1508e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* base_address = NULL;
1518e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char path[PATH_MAX];
1528e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  snprintf(path, sizeof(path), "/proc/%d/maps", getpid());
1538e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char line[BUFSIZ];
1548e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  FILE* fp = fopen(path, "r");
1558e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(fp != NULL);
1568e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  while (fgets(line, sizeof(line), fp) != NULL) {
1578e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    uintptr_t start = strtoul(line, 0, 16);
1588e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
1598e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    char* path = strchr(line, '/');
160156da966214957c5616a0b83cc84686eedfc4e31Elliott Hughes    if (path != NULL && strcmp(executable_path, path) == 0) {
1618e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      base_address = reinterpret_cast<void*>(start);
1628e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
1638e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
1648e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
1658e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  fclose(fp);
1668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1678e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
1688e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
1698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
1708e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1718e15b08ae22a5230c1fea4779410de0420fa939cElliott HughesTEST(dlopen, dladdr_invalid) {
1728e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
1738e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1743b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
1753b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1768e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
1778e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
1783b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
1798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
1818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
1823b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
1838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
184