Merge "Add stpcpy assembler version."
diff --git a/libc/include/elf.h b/libc/include/elf.h
index 7a9485a..7de464e 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -54,6 +54,35 @@
 #define DF_BIND_NOW   0x00000008
 #define DF_STATIC_TLS 0x00000010
 
+#define DF_1_NOW        0x00000001 // Perform complete relocation processing.
+#define DF_1_GLOBAL     0x00000002 // implies RTLD_GLOBAL
+#define DF_1_GROUP      0x00000004
+#define DF_1_NODELETE   0x00000008 // implies RTLD_NODELETE
+#define DF_1_LOADFLTR   0x00000010
+#define DF_1_INITFIRST  0x00000020
+#define DF_1_NOOPEN     0x00000040 // Object can not be used with dlopen(3)
+#define DF_1_ORIGIN     0x00000080
+#define DF_1_DIRECT     0x00000100
+#define DF_1_TRANS      0x00000200
+#define DF_1_INTERPOSE  0x00000400
+#define DF_1_NODEFLIB   0x00000800
+#define DF_1_NODUMP     0x00001000 // Object cannot be dumped with dldump(3)
+#define DF_1_CONFALT    0x00002000
+#define DF_1_ENDFILTEE  0x00004000
+#define DF_1_DISPRELDNE 0x00008000
+#define DF_1_DISPRELPND 0x00010000
+#define DF_1_NODIRECT   0x00020000
+#define DF_1_IGNMULDEF  0x00040000 // Internal use
+#define DF_1_NOKSYMS    0x00080000 // Internal use
+#define DF_1_NOHDR      0x00100000 // Internal use
+#define DF_1_EDITED     0x00200000
+#define DF_1_NORELOC    0x00400000 // Internal use
+#define DF_1_SYMINTPOSE 0x00800000
+#define DF_1_GLOBAUDIT  0x01000000
+#define DF_1_SINGLETON  0x02000000
+#define DF_1_STUB       0x04000000
+#define DF_1_PIE        0x08000000
+
 #define DT_BIND_NOW 24
 #define DT_INIT_ARRAY 25
 #define DT_FINI_ARRAY 26
diff --git a/libc/tools/zoneinfo/update-tzdata.py b/libc/tools/zoneinfo/update-tzdata.py
index e800e8f..f5681be 100755
--- a/libc/tools/zoneinfo/update-tzdata.py
+++ b/libc/tools/zoneinfo/update-tzdata.py
@@ -123,18 +123,21 @@
   print 'Making ICU data...'
   subprocess.check_call(['make'])
 
-  # Copy the output files to their ultimate destination.
+  # Copy the source file to its ultimate destination.
   icu_txt_data_dir = '%s/data/misc' % icu_dir
   print 'Copying zoneinfo64.txt to %s ...' % icu_txt_data_dir
   shutil.copy('zoneinfo64.txt', icu_txt_data_dir)
 
+  # Regenerate the .dat file.
   os.chdir(icu_working_dir)
+  subprocess.check_call(['make', '-j32'])
+
+  # Copy the .dat file to its ultimate destination.
   icu_dat_data_dir = '%s/stubdata' % icu_dir
   datfiles = glob.glob('data/out/tmp/icudt??l.dat')
   if len(datfiles) != 1:
     print 'ERROR: Unexpectedly found %d .dat files (%s). Halting.' % (len(datfiles), datfiles)
     sys.exit(1)
-
   datfile = datfiles[0]
   print 'Copying %s to %s ...' % (datfile, icu_dat_data_dir)
   shutil.copy(datfile, icu_dat_data_dir)
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/realpath.c b/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
index 8fd5457..c4bd953 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
@@ -132,26 +132,7 @@
 			resolved[resolved_len] = '\0';
 		}
 		if (next_token[0] == '\0') {
-			/*
-			 * Handle consequential slashes.  The path
-			 * before slash shall point to a directory.
-			 *
-			 * Only the trailing slashes are not covered
-			 * by other checks in the loop, but we verify
-			 * the prefix for any (rare) "//" or "/\0"
-			 * occurence to not implement lookahead.
-			 */
-			if (lstat(resolved, &sb) != 0) {
-				if (m)
-					free(resolved);
-				return (NULL);
-			}
-			if (!S_ISDIR(sb.st_mode)) {
-				if (m)
-					free(resolved);
-				errno = ENOTDIR;
-				return (NULL);
-			}
+			/* Handle consequential slashes. */
 			continue;
 		}
 		else if (strcmp(next_token, ".") == 0)
@@ -236,6 +217,11 @@
 				}
 			}
 			left_len = strlcpy(left, symlink, sizeof(left));
+		} else if (!S_ISDIR(sb.st_mode) && p != NULL) {
+			if (m)
+				free(resolved);
+			errno = ENOTDIR;
+			return (NULL);
 		}
 	}
 
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index 8d574f5..33bfe6b 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/libm/Android.mk b/libm/Android.mk
index 60f4cb8..69a17a1 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -1,6 +1,8 @@
 ifneq ($(TARGET_USE_PRIVATE_LIBM),true)
 LOCAL_PATH:= $(call my-dir)
 
+bionic_coverage := false
+
 # TODO: this comes from from upstream's libc, not libm, but it's an
 # implementation detail that should have hidden visibility, so it needs
 # to be in whatever library the math code is in.
@@ -273,6 +275,8 @@
 LOCAL_SRC_FILES := $(libm_common_src_files)
 LOCAL_SYSTEM_SHARED_LIBRARIES := libc
 
+LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+
 # arch-specific settings
 LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/arm
 LOCAL_SRC_FILES_arm := arm/fenv.c
@@ -306,6 +310,8 @@
 LOCAL_SYSTEM_SHARED_LIBRARIES := libc
 LOCAL_WHOLE_STATIC_LIBRARIES := libm
 
+LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+
 # We'd really like to do this for all architectures, but since this wasn't done
 # before, these symbols must continue to be exported on LP32 for binary
 # compatibility.
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index c930ce9..98931c7 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -147,7 +147,7 @@
   // Determine if any symbol in the library contains the specified address.
   ElfW(Sym)* sym = dladdr_find_symbol(si, addr);
   if (sym != nullptr) {
-    info->dli_sname = si->strtab + sym->st_name;
+    info->dli_sname = si->get_string(sym->st_name);
     info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
   }
 
@@ -245,6 +245,7 @@
     __libdl_info.bucket = g_libdl_buckets;
     __libdl_info.chain = g_libdl_chains;
     __libdl_info.ref_count = 1;
+    __libdl_info.strtab_size = sizeof(ANDROID_LIBDL_STRTAB);
   }
 
   return &__libdl_info;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 5b39668..6c30e1c 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -417,14 +417,13 @@
 
 static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
   ElfW(Sym)* symtab = si->symtab;
-  const char* strtab = si->strtab;
 
   TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd",
              name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
 
   for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
     ElfW(Sym)* s = symtab + n;
-    if (strcmp(strtab + s->st_name, name)) continue;
+    if (strcmp(si->get_string(s->st_name), name)) continue;
 
     // only concern ourselves with global and weak symbol definitions
     switch (ELF_ST_BIND(s->st_info)) {
@@ -775,7 +774,7 @@
 static void for_each_dt_needed(const soinfo* si, F action) {
   for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
     if (d->d_tag == DT_NEEDED) {
-      action(si->strtab + d->d_un.d_val);
+      action(si->get_string(d->d_un.d_val));
     }
   }
 }
@@ -1085,7 +1084,7 @@
     soinfo* lsi = nullptr;
 
     if (sym != 0) {
-      sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+      sym_name = get_string(symtab[sym].st_name);
       s = soinfo_do_lookup(this, sym_name, &lsi);
       if (s == nullptr) {
         // We only allow an undefined symbol if this is a weak reference...
@@ -1363,7 +1362,7 @@
     soinfo* lsi = nullptr;
 
     if (sym != 0) {
-      sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+      sym_name = get_string(symtab[sym].st_name);
       s = soinfo_do_lookup(this, sym_name, &lsi);
       if (s == nullptr) {
         // We only allow an undefined symbol if this is a weak reference...
@@ -1581,7 +1580,7 @@
   got = si->plt_got + local_gotno;
   for (size_t g = gotsym; g < symtabno; g++, sym++, got++) {
     // This is an undefined reference... try to locate it.
-    const char* sym_name = si->strtab + sym->st_name;
+    const char* sym_name = si->get_string(sym->st_name);
     soinfo* lsi = nullptr;
     ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi);
     if (s == nullptr) {
@@ -1787,6 +1786,14 @@
   return static_cast<ElfW(Addr)>(s->st_value + load_bias);
 }
 
+const char* soinfo::get_string(ElfW(Word) index) const {
+  if (has_min_version(1) && (index >= strtab_size)) {
+    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", name, strtab_size, index);
+  }
+
+  return strtab + index;
+}
+
 /* Force any of the closed stdin, stdout and stderr to be associated with
    /dev/null. */
 static int nullify_closed_stdio() {
@@ -1895,6 +1902,9 @@
       case DT_STRTAB:
         strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
         break;
+      case DT_STRSZ:
+        strtab_size = d->d_un.d_val;
+        break;
       case DT_SYMTAB:
         symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
         break;
@@ -2048,9 +2058,17 @@
           has_DT_SYMBOLIC = true;
         }
         break;
-#if defined(__mips__)
-      case DT_STRSZ:
+      case DT_FLAGS_1:
+        if ((d->d_un.d_val & DF_1_GLOBAL) != 0) {
+          rtld_flags |= RTLD_GLOBAL;
+        }
+        // TODO: Implement other flags
+
+        if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) {
+          DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val));
+        }
         break;
+#if defined(__mips__)
       case DT_MIPS_RLD_MAP:
         // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
         {
@@ -2079,7 +2097,7 @@
 
       default:
         if (!relocating_linker) {
-          DEBUG("%s: unused DT entry: type %p arg %p", name,
+          DL_WARN("%s: unused DT entry: type %p arg %p", name,
               reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
         }
         break;
diff --git a/linker/linker.h b/linker/linker.h
index 2896933..f6e3a48 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -136,7 +136,9 @@
   soinfo* next;
   unsigned flags;
 
+ private:
   const char* strtab;
+ public:
   ElfW(Sym)* symtab;
 
   size_t nbucket;
@@ -222,7 +224,9 @@
 
   ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s);
 
-  bool inline has_min_version(uint32_t min_version) {
+  const char* get_string(ElfW(Word) index) const;
+
+  bool inline has_min_version(uint32_t min_version) const {
     return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version;
   }
  private:
@@ -249,6 +253,9 @@
 
   // version >= 1
   int rtld_flags;
+  size_t strtab_size;
+
+  friend soinfo* get_libdl_info();
 };
 
 extern soinfo* get_libdl_info();
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 9dbb4f5..01de09f 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -38,37 +38,71 @@
   ASSERT_EQ(EINVAL, pthread_key_delete(key));
 }
 
-TEST(pthread, pthread_key_create_lots) {
-#if defined(__BIONIC__) // glibc uses keys internally that its sysconf value doesn't account for.
+TEST(pthread, pthread_keys_max) {
   // POSIX says PTHREAD_KEYS_MAX should be at least 128.
   ASSERT_GE(PTHREAD_KEYS_MAX, 128);
+}
 
+TEST(pthread, _SC_THREAD_KEYS_MAX_big_enough_for_POSIX) {
+  // sysconf shouldn't return a smaller value.
+  int sysconf_max = sysconf(_SC_THREAD_KEYS_MAX);
+  ASSERT_GE(sysconf_max, PTHREAD_KEYS_MAX);
+}
+
+TEST(pthread, pthread_key_many_distinct) {
+  // We should be able to allocate at least this many keys.
+  int nkeys = sysconf(_SC_THREAD_KEYS_MAX) / 2;
+  std::vector<pthread_key_t> keys;
+
+  auto scope_guard = make_scope_guard([&keys]{
+    for (auto key : keys) {
+      EXPECT_EQ(0, pthread_key_delete(key));
+    }
+  });
+
+  for (int i = 0; i < nkeys; ++i) {
+    pthread_key_t key;
+    // If this fails, it's likely that GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT is
+    // wrong.
+    ASSERT_EQ(0, pthread_key_create(&key, NULL)) << i << " of " << nkeys;
+    keys.push_back(key);
+    ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void*>(i)));
+  }
+
+  for (int i = keys.size() - 1; i >= 0; --i) {
+    ASSERT_EQ(reinterpret_cast<void*>(i), pthread_getspecific(keys.back()));
+    pthread_key_t key = keys.back();
+    keys.pop_back();
+    ASSERT_EQ(0, pthread_key_delete(key));
+  }
+}
+
+TEST(pthread, pthread_key_EAGAIN) {
   int sysconf_max = sysconf(_SC_THREAD_KEYS_MAX);
 
-  // sysconf shouldn't return a smaller value.
-  ASSERT_GE(sysconf_max, PTHREAD_KEYS_MAX);
-
-  // We can allocate _SC_THREAD_KEYS_MAX keys.
-  sysconf_max -= 2; // (Except that gtest takes two for itself.)
   std::vector<pthread_key_t> keys;
-  for (int i = 0; i < sysconf_max; ++i) {
+  int rv = 0;
+  // Two keys are used by gtest, so sysconf_max should be more than we are
+  // allowed to allocate now.
+  for (int i = 0; i < sysconf_max; i++) {
     pthread_key_t key;
-    // If this fails, it's likely that GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT is wrong.
-    ASSERT_EQ(0, pthread_key_create(&key, NULL)) << i << " of " << sysconf_max;
+    rv = pthread_key_create(&key, NULL);
+    if (rv == EAGAIN) {
+      break;
+    }
+    EXPECT_EQ(0, rv);
     keys.push_back(key);
   }
 
-  // ...and that really is the maximum.
-  pthread_key_t key;
-  ASSERT_EQ(EAGAIN, pthread_key_create(&key, NULL));
-
-  // (Don't leak all those keys!)
-  for (size_t i = 0; i < keys.size(); ++i) {
-    ASSERT_EQ(0, pthread_key_delete(keys[i]));
+  // Don't leak keys.
+  for (auto key : keys) {
+    EXPECT_EQ(0, pthread_key_delete(key));
   }
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
+  keys.clear();
+
+  // We should have eventually reached the maximum number of keys and received
+  // EAGAIN.
+  ASSERT_EQ(EAGAIN, rv);
 }
 
 TEST(pthread, pthread_key_delete) {
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index e814ef7..9ad96fd 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -99,6 +99,18 @@
   ASSERT_EQ(ENOENT, errno);
 }
 
+TEST(stdlib, realpath__component_after_non_directory) {
+  errno = 0;
+  char* p = realpath("/dev/null/.", NULL);
+  ASSERT_TRUE(p == NULL);
+  ASSERT_EQ(ENOTDIR, errno);
+
+  errno = 0;
+  p = realpath("/dev/null/..", NULL);
+  ASSERT_TRUE(p == NULL);
+  ASSERT_EQ(ENOTDIR, errno);
+}
+
 TEST(stdlib, realpath) {
   // Get the name of this executable.
   char executable_path[PATH_MAX];