Merge "Fix pthread benchmarks."
diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c
index 7b858ae..b6a3077 100644
--- a/libc/stdio/fread.c
+++ b/libc/stdio/fread.c
@@ -43,6 +43,8 @@
 size_t
 fread(void *buf, size_t size, size_t count, FILE *fp) __overloadable
 {
+	CHECK_FP(fp);
+
 	/*
 	 * Extension:  Catch integer overflow.
 	 */
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index bf6a8f8..02ea8f8 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -38,6 +38,9 @@
 #include <pthread.h>
 #include <stdbool.h>
 #include <wchar.h>
+
+#include <async_safe/log.h>
+
 #include "wcio.h"
 
 /*
@@ -252,4 +255,13 @@
 
 __END_DECLS
 
+// Sanity check a FILE* for nullptr, so we can emit a message while crashing
+// instead of doing a blind null-dereference.
+#define CHECK_FP(fp)                                                       \
+  do {                                                                     \
+    if (__predict_false(fp == 0)) {                                        \
+      async_safe_fatal("invalid FILE* %p passed to %s", fp, __FUNCTION__); \
+    }                                                                      \
+  } while (0)
+
 #endif
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index 4d6438b..cf97a3f 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -44,6 +44,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "local.h"
 #include "glue.h"
 #include "private/bionic_fortify.h"
@@ -261,6 +263,7 @@
 // all possible, no matter what.
 // TODO: rewrite this mess completely.
 FILE* freopen(const char* file, const char* mode, FILE* fp) {
+  CHECK_FP(fp);
   int mode_flags;
   int flags = __sflags(mode, &mode_flags);
   if (flags == 0) {
@@ -361,6 +364,7 @@
 __strong_alias(freopen64, freopen);
 
 int fclose(FILE* fp) {
+  CHECK_FP(fp);
   if (fp->_flags == 0) {
     // Already freed!
     errno = EBADF;
@@ -387,6 +391,7 @@
 }
 
 int fileno_unlocked(FILE* fp) {
+  CHECK_FP(fp);
   int fd = fp->_file;
   if (fd == -1) {
     errno = EBADF;
@@ -396,6 +401,7 @@
 }
 
 int fileno(FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   return fileno_unlocked(fp);
 }
@@ -405,24 +411,29 @@
 }
 
 void clearerr(FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   clearerr_unlocked(fp);
 }
 
 int feof_unlocked(FILE* fp) {
+  CHECK_FP(fp);
   return ((fp->_flags & __SEOF) != 0);
 }
 
 int feof(FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   return feof_unlocked(fp);
 }
 
 int ferror_unlocked(FILE* fp) {
+  CHECK_FP(fp);
   return __sferror(fp);
 }
 
 int ferror(FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   return ferror_unlocked(fp);
 }
@@ -533,24 +544,29 @@
 }
 
 int fseeko(FILE* fp, off_t offset, int whence) {
+  CHECK_FP(fp);
   static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
   return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
 }
 __strong_alias(fseek, fseeko);
 
 int fseeko64(FILE* fp, off64_t offset, int whence) {
+  CHECK_FP(fp);
   return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
 }
 
 int fsetpos(FILE* fp, const fpos_t* pos) {
+  CHECK_FP(fp);
   return fseeko(fp, *pos, SEEK_SET);
 }
 
 int fsetpos64(FILE* fp, const fpos64_t* pos) {
+  CHECK_FP(fp);
   return fseeko64(fp, *pos, SEEK_SET);
 }
 
 off_t ftello(FILE* fp) {
+  CHECK_FP(fp);
   static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
   off64_t result = ftello64(fp);
   if (result > LONG_MAX) {
@@ -562,16 +578,19 @@
 __strong_alias(ftell, ftello);
 
 off64_t ftello64(FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   return __ftello64_unlocked(fp);
 }
 
 int fgetpos(FILE* fp, fpos_t* pos) {
+  CHECK_FP(fp);
   *pos = ftello(fp);
   return (*pos == -1) ? -1 : 0;
 }
 
 int fgetpos64(FILE* fp, fpos64_t* pos) {
+  CHECK_FP(fp);
   *pos = ftello64(fp);
   return (*pos == -1) ? -1 : 0;
 }
@@ -642,35 +661,43 @@
 }
 
 int fprintf(FILE* fp, const char* fmt, ...) {
+  CHECK_FP(fp);
   PRINTF_IMPL(vfprintf(fp, fmt, ap));
 }
 
 int fgetc(FILE* fp) {
+  CHECK_FP(fp);
   return getc(fp);
 }
 
 int fputc(int c, FILE* fp) {
+  CHECK_FP(fp);
   return putc(c, fp);
 }
 
 int fscanf(FILE* fp, const char* fmt, ...) {
+  CHECK_FP(fp);
   PRINTF_IMPL(vfscanf(fp, fmt, ap));
 }
 
 int fwprintf(FILE* fp, const wchar_t* fmt, ...) {
+  CHECK_FP(fp);
   PRINTF_IMPL(vfwprintf(fp, fmt, ap));
 }
 
 int fwscanf(FILE* fp, const wchar_t* fmt, ...) {
+  CHECK_FP(fp);
   PRINTF_IMPL(vfwscanf(fp, fmt, ap));
 }
 
 int getc(FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   return getc_unlocked(fp);
 }
 
 int getc_unlocked(FILE* fp) {
+  CHECK_FP(fp);
   return __sgetc(fp);
 }
 
@@ -683,10 +710,12 @@
 }
 
 ssize_t getline(char** buf, size_t* len, FILE* fp) {
+  CHECK_FP(fp);
   return getdelim(buf, len, '\n', fp);
 }
 
 wint_t getwc(FILE* fp) {
+  CHECK_FP(fp);
   return fgetwc(fp);
 }
 
@@ -699,11 +728,13 @@
 }
 
 int putc(int c, FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   return putc_unlocked(c, fp);
 }
 
 int putc_unlocked(int c, FILE* fp) {
+  CHECK_FP(fp);
   if (cantwrite(fp)) {
     errno = EBADF;
     return EOF;
@@ -724,6 +755,7 @@
 }
 
 wint_t putwc(wchar_t wc, FILE* fp) {
+  CHECK_FP(fp);
   return fputwc(wc, fp);
 }
 
@@ -738,6 +770,7 @@
 }
 
 void rewind(FILE* fp) {
+  CHECK_FP(fp);
   ScopedFileLock sfl(fp);
   fseek(fp, 0, SEEK_SET);
   clearerr_unlocked(fp);
@@ -748,14 +781,17 @@
 }
 
 void setbuf(FILE* fp, char* buf) {
+  CHECK_FP(fp);
   setbuffer(fp, buf, BUFSIZ);
 }
 
 void setbuffer(FILE* fp, char* buf, int size) {
+  CHECK_FP(fp);
   setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size);
 }
 
 int setlinebuf(FILE* fp) {
+  CHECK_FP(fp);
   return setvbuf(fp, nullptr, _IOLBF, 0);
 }
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index ec92c92..5f906c8 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1433,6 +1433,8 @@
 
   if (search_linked_namespaces) {
     // if a library was not found - look into linked namespaces
+    // preserve current dlerror in the case it fails.
+    DlErrorRestorer dlerror_restorer;
     for (auto& linked_namespace : ns->linked_namespaces()) {
       if (find_library_in_linked_namespace(linked_namespace,
                                            task)) {
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index e036c05..f7d2c53 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -43,6 +43,9 @@
 #include <string>
 #include <unordered_map>
 
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
 class ConfigParser {
  public:
   enum {
@@ -275,6 +278,15 @@
   return true;
 }
 
+static std::string getVndkVersionString() {
+  char vndk_version_str[1 + PROP_VALUE_MAX] = {};
+  __system_property_get("ro.vndk.version", vndk_version_str + 1);
+  if (strlen(vndk_version_str + 1) != 0 && strcmp(vndk_version_str + 1, "current") != 0) {
+    vndk_version_str[0] = '-';
+  }
+  return vndk_version_str;
+}
+
 static Config g_config;
 
 static constexpr const char* kDefaultConfigName = "default";
@@ -334,6 +346,9 @@
       params.push_back({ "SDK_VER", buf });
     }
 
+    static std::string vndk = getVndkVersionString();
+    params.push_back({ "VNDK_VER", vndk });
+
     for (auto&& path : paths) {
       format_string(&path, params);
     }
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index d8134af..11ccbd5 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -32,6 +32,7 @@
 #include <link.h>
 #include <stddef.h>
 
+#include <string>
 #include <unordered_map>
 
 #include <async_safe/log.h>
@@ -39,7 +40,6 @@
 #define DL_ERR(fmt, x...) \
     do { \
       async_safe_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
-      /* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
     } while (false)
 
 #define DL_WARN(fmt, x...) \
@@ -75,4 +75,16 @@
 char* linker_get_error_buffer();
 size_t linker_get_error_buffer_size();
 
+class DlErrorRestorer {
+ public:
+  DlErrorRestorer() {
+    saved_error_msg_ = linker_get_error_buffer();
+  }
+  ~DlErrorRestorer() {
+    strlcpy(linker_get_error_buffer(), saved_error_msg_.c_str(), linker_get_error_buffer_size());
+  }
+ private:
+  std::string saved_error_msg_;
+};
+
 #endif  /* __LINKER_GLOBALS_H */
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 7028ca7..3f6da59 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -1589,6 +1589,54 @@
   ASSERT_STREQ("dlopen failed: library \"libnstest_public.so\" not found", dlerror());
 }
 
+TEST(dlext, ns_inaccessible_error_message) {
+  // We set up 2 namespaces (a and b) and link a->b with a shared library
+  // libtestshared.so. Then try to dlopen different library with the same
+  // name from in namespace a. Note that library should not be accessible
+  // in either namespace but since it's soname is in the list of shared libs
+  // the linker will attempt to find it in linked namespace.
+  //
+  // Check the error message and make sure it mentions correct namespace name.
+  ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+  android_namespace_t* ns_a =
+          android_create_namespace("ns_a",
+                                   nullptr,
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   nullptr,
+                                   nullptr);
+  ASSERT_TRUE(ns_a != nullptr) << dlerror();
+  ASSERT_TRUE(android_link_namespaces(ns_a, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+  android_namespace_t* ns_b =
+          android_create_namespace("ns_b",
+                                   nullptr,
+                                   get_testlib_root().c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   nullptr,
+                                   nullptr);
+  ASSERT_TRUE(ns_b != nullptr) << dlerror();
+  ASSERT_TRUE(android_link_namespaces(ns_b, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+  ASSERT_TRUE(android_link_namespaces(ns_a, ns_b, "libtestshared.so")) << dlerror();
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns_a;
+
+  std::string library_path = get_testlib_root() + "/inaccessible_libs/libtestshared.so";
+
+  void* handle = android_dlopen_ext(library_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle == nullptr);
+  std::string expected_dlerror =
+      android::base::StringPrintf("dlopen failed: library \"%s\" needed or dlopened by \"%s\""
+                                  " is not accessible for the namespace \"ns_a\"",
+                                  library_path.c_str(),
+                                  get_executable_path().c_str());
+  ASSERT_EQ(expected_dlerror, dlerror());
+}
+
 TEST(dlext, ns_anonymous) {
   static const char* root_lib = "libnstest_root.so";
   std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index ba0b1aa..5f27387 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -440,6 +440,16 @@
 }
 
 // -----------------------------------------------------------------------------
+// Library for inaccessible shared library test
+// -----------------------------------------------------------------------------
+cc_test_library {
+    name: "libtestshared",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["empty.cpp"],
+    relative_install_path: "/inaccessible_libs",
+}
+
+// -----------------------------------------------------------------------------
 // Library with weak undefined function
 // -----------------------------------------------------------------------------
 cc_test_library {
diff --git a/tests/limits_test.cpp b/tests/limits_test.cpp
index ed42dbb..e5902ad 100644
--- a/tests/limits_test.cpp
+++ b/tests/limits_test.cpp
@@ -20,7 +20,7 @@
 
 TEST(limits, macros) {
   ASSERT_EQ(8, CHAR_BIT);
-  ASSERT_EQ(static_cast<int>(sizeof(int)), WORD_BIT);
+  ASSERT_EQ(8 * static_cast<int>(sizeof(int)), WORD_BIT);
   ASSERT_EQ(20, NZERO);
 #if !defined(MB_LEN_MAX)
 #error MB_LEN_MAX