Merge "Fix over read in strcpy/stpcpy/strcat."
diff --git a/libc/Android.mk b/libc/Android.mk
index 175fbb4..3435c3f 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -1387,6 +1387,10 @@
 # compatibility.
 LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
 
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
 # TODO: This is to work around b/19059885. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
@@ -1455,6 +1459,10 @@
 # Don't re-export new/delete and friends, even if the compiler really wants to.
 LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
 
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
 LOCAL_SANITIZE := never
@@ -1495,6 +1503,10 @@
 # Don't re-export new/delete and friends, even if the compiler really wants to.
 LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
 
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
 LOCAL_SANITIZE := never
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index de72cb2..6fb8ebe 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -50,14 +50,11 @@
   uintptr_t offset;
   char permissions[4];
   int name_pos;
-  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start,
+  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start,
              &end, permissions, &offset, &name_pos) < 2) {
     return NULL;
   }
 
-  while (isspace(line[name_pos])) {
-    name_pos += 1;
-  }
   const char* name = line + name_pos;
   size_t name_len = strlen(name);
   if (name_len && name[name_len - 1] == '\n') {
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 3b91e6a..6a39a21 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -130,8 +130,13 @@
  */
 #define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGSTKSZ)
 
-/* Leave room for a guard page in the internally created signal stacks. */
+// Leave room for a guard page in the internally created signal stacks.
+#if defined(__LP64__)
+// SIGSTKSZ is not big enough for 64-bit arch. See http://b/23041777.
+#define SIGNAL_STACK_SIZE (16 * 1024 + PAGE_SIZE)
+#else
 #define SIGNAL_STACK_SIZE (SIGSTKSZ + PAGE_SIZE)
+#endif
 
 /* Needed by fork. */
 __LIBC_HIDDEN__ extern void __bionic_atfork_run_prepare();
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 41c78bc..0340f0e 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -206,7 +206,7 @@
 // u0_a1234 -> 0 * AID_USER + AID_APP + 1234
 // u2_i1000 -> 2 * AID_USER + AID_ISOLATED_START + 1000
 // u1_system -> 1 * AID_USER + android_ids['system']
-// returns 0 and sets errno to ENOENT in case of error
+// returns 0 and sets errno to ENOENT in case of error.
 static id_t app_id_from_name(const char* name, bool is_group) {
   char* end;
   unsigned long userid;
@@ -312,6 +312,54 @@
   }
 }
 
+// Translate an OEM name to the corresponding user/group id.
+// oem_XXX -> AID_OEM_RESERVED_2_START + XXX, iff XXX is within range.
+static id_t oem_id_from_name(const char* name) {
+  unsigned int id;
+  if (sscanf(name, "oem_%u", &id) != 1) {
+    return 0;
+  }
+  // Check OEM id is within range.
+  if (id > (AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START)) {
+    return 0;
+  }
+  return AID_OEM_RESERVED_2_START + static_cast<id_t>(id);
+}
+
+static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) {
+  if (uid < AID_OEM_RESERVED_2_START || uid > AID_OEM_RESERVED_2_END) {
+    return NULL;
+  }
+
+  snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u",
+           uid - AID_OEM_RESERVED_2_START);
+  snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
+  snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
+
+  passwd* pw = &state->passwd_;
+  pw->pw_name  = state->name_buffer_;
+  pw->pw_dir   = state->dir_buffer_;
+  pw->pw_shell = state->sh_buffer_;
+  pw->pw_uid   = uid;
+  pw->pw_gid   = uid;
+  return pw;
+}
+
+static group* oem_id_to_group(gid_t gid, group_state_t* state) {
+  if (gid < AID_OEM_RESERVED_2_START || gid > AID_OEM_RESERVED_2_END) {
+    return NULL;
+  }
+
+  snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_),
+           "oem_%u", gid - AID_OEM_RESERVED_2_START);
+
+  group* gr = &state->group_;
+  gr->gr_name   = state->group_name_buffer_;
+  gr->gr_gid    = gid;
+  gr->gr_mem[0] = gr->gr_name;
+  return gr;
+}
+
 // Translate a uid into the corresponding name.
 // 0 to AID_APP-1                   -> "system", "radio", etc.
 // AID_APP to AID_ISOLATED_START-1  -> u0_a1234
@@ -371,6 +419,11 @@
   if (pw != NULL) {
     return pw;
   }
+  // Handle OEM range.
+  pw = oem_id_to_passwd(uid, state);
+  if (pw != NULL) {
+    return pw;
+  }
   return app_id_to_passwd(uid, state);
 }
 
@@ -384,6 +437,11 @@
   if (pw != NULL) {
     return pw;
   }
+  // Handle OEM range.
+  pw = oem_id_to_passwd(oem_id_from_name(login), state);
+  if (pw != NULL) {
+    return pw;
+  }
   return app_id_to_passwd(app_id_from_name(login, false), state);
 }
 
@@ -407,6 +465,11 @@
   if (grp != NULL) {
     return grp;
   }
+  // Handle OEM range.
+  grp = oem_id_to_group(gid, state);
+  if (grp != NULL) {
+    return grp;
+  }
   return app_id_to_group(gid, state);
 }
 
@@ -423,6 +486,11 @@
   if (grp != NULL) {
     return grp;
   }
+  // Handle OEM range.
+  grp = oem_id_to_group(oem_id_from_name(name), state);
+  if (grp != NULL) {
+    return grp;
+  }
   return app_id_to_group(app_id_from_name(name, true), state);
 }
 
diff --git a/libc/include/netinet/udp.h b/libc/include/netinet/udp.h
index 25e0dfc..d4eb368 100644
--- a/libc/include/netinet/udp.h
+++ b/libc/include/netinet/udp.h
@@ -25,31 +25,29 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _NETINET_UDP_H
 #define _NETINET_UDP_H
 
-/*
- * We would include linux/udp.h, but it brings in too much other stuff
- */
+#include <sys/types.h>
 
-#ifdef __FAVOR_BSD
+#include <linux/udp.h>
 
 struct udphdr {
-    u_int16_t uh_sport;	/* source port */
-    u_int16_t uh_dport;	/* destination port */
-    u_int16_t uh_ulen;	/* udp length */
-    u_int16_t uh_sum;	/* udp checksum */
+    __extension__ union {
+        struct /* BSD names */ {
+            u_int16_t uh_sport;
+            u_int16_t uh_dport;
+            u_int16_t uh_ulen;
+            u_int16_t uh_sum;
+        };
+        struct /* Linux names */ {
+            u_int16_t source;
+            u_int16_t dest;
+            u_int16_t len;
+            u_int16_t check;
+        };
+    };
 };
 
-#else
-
-struct udphdr {
-    __u16  source;
-    __u16  dest;
-    __u16  len;
-    __u16  check;
-};
-
-#endif /* __FAVOR_BSD */
-
 #endif /* _NETINET_UDP_H */
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 3ad4f42..58038cd 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -130,30 +130,9 @@
 #define	__volatile
 #endif	/* !__GNUC__ */
 
-/*
- * In non-ANSI C environments, new programs will want ANSI-only C keywords
- * deleted from the program and old programs will want them left alone.
- * Programs using the ANSI C keywords const, inline etc. as normal
- * identifiers should define -DNO_ANSI_KEYWORDS.
- */
-#ifndef	NO_ANSI_KEYWORDS
-#define	const		__const		/* convert ANSI C keywords */
-#define	inline		__inline
-#define	signed		__signed
-#define	volatile	__volatile
-#endif /* !NO_ANSI_KEYWORDS */
 #endif	/* !(__STDC__ || __cplusplus) */
 
 /*
- * Used for internal auditing of the NetBSD source tree.
- */
-#ifdef __AUDIT__
-#define	__aconst	__const
-#else
-#define	__aconst
-#endif
-
-/*
  * The following macro is used to remove const cast-away warnings
  * from gcc -Wcast-qual; it should be used with caution because it
  * can hide valid errors; in particular most valid uses are in
@@ -164,75 +143,19 @@
  */
 #define __UNCONST(a)	((void *)(unsigned long)(const void *)(a))
 
-/*
- * GCC2 provides __extension__ to suppress warnings for various GNU C
- * language extensions under "-ansi -pedantic".
- */
-#if !__GNUC_PREREQ(2, 0)
-#define	__extension__		/* delete __extension__ if non-gcc or gcc1 */
-#endif
-
-/*
- * GCC1 and some versions of GCC2 declare dead (non-returning) and
- * pure (no side effects) functions using "volatile" and "const";
- * unfortunately, these then cause warnings under "-ansi -pedantic".
- * GCC2 uses a new, peculiar __attribute__((attrs)) style.  All of
- * these work for GNU C++ (modulo a slight glitch in the C++ grammar
- * in the distribution version of 2.5.5).
- */
-#if !__GNUC_PREREQ(2, 5)
-#define	__attribute__(x)	/* delete __attribute__ if non-gcc or gcc1 */
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-#define	__dead		__volatile
-#define	__pure		__const
-#endif
-#endif
-
-/* Delete pseudo-keywords wherever they are not available or needed. */
-#ifndef __dead
-#define	__dead
-#define	__pure
-#endif
-
-#if __GNUC_PREREQ(2, 7)
-#define	__unused	__attribute__((__unused__))
-#else
-#define	__unused	/* delete */
-#endif
-
+#define __dead __attribute__((__noreturn__))
+#define __pure __attribute__((__const__))
 #define __pure2 __attribute__((__const__)) /* Android-added: used by FreeBSD libm */
 
-#if __GNUC_PREREQ(3, 1)
-#define	__used		__attribute__((__used__))
-#else
-#define	__used		/* delete */
-#endif
+#define	__unused	__attribute__((__unused__))
 
-#if __GNUC_PREREQ(2, 7)
+#define	__used		__attribute__((__used__))
+
 #define	__packed	__attribute__((__packed__))
 #define	__aligned(x)	__attribute__((__aligned__(x)))
 #define	__section(x)	__attribute__((__section__(x)))
-#elif defined(__lint__)
-#define	__packed	/* delete */
-#define	__aligned(x)	/* delete */
-#define	__section(x)	/* delete */
-#else
-#define	__packed	error: no __packed for this compiler
-#define	__aligned(x)	error: no __aligned for this compiler
-#define	__section(x)	error: no __section for this compiler
-#endif
 
-#if !__GNUC_PREREQ(2, 8)
-#define	__extension__
-#endif
-
-#if __GNUC_PREREQ(2, 8)
 #define __statement(x)	__extension__(x)
-#elif defined(lint)
-#define __statement(x)	(0)
-#else
-#define __statement(x)	(x)
-#endif
 
 #define __nonnull(args) __attribute__((__nonnull__ args))
 
@@ -240,43 +163,20 @@
 #define __scanflike(x, y) __attribute__((__format__(scanf, x, y))) __nonnull((x))
 
 /*
- * C99 defines the restrict type qualifier keyword, which was made available
- * in GCC 2.92.
+ * C99 defines the restrict type qualifier keyword.
  */
 #if defined(__STDC__VERSION__) && __STDC_VERSION__ >= 199901L
 #define	__restrict	restrict
-#else
-#if !__GNUC_PREREQ(2, 92)
-#define	__restrict	/* delete __restrict when not supported */
-#endif
 #endif
 
 /*
- * C99 defines __func__ predefined identifier, which was made available
- * in GCC 2.95.
+ * C99 defines __func__ predefined identifier.
  */
 #if !defined(__STDC_VERSION__) || !(__STDC_VERSION__ >= 199901L)
-#if __GNUC_PREREQ(2, 6)
 #define	__func__	__PRETTY_FUNCTION__
-#elif __GNUC_PREREQ(2, 4)
-#define	__func__	__FUNCTION__
-#else
-#define	__func__	""
-#endif
 #endif /* !(__STDC_VERSION__ >= 199901L) */
 
 /*
- * A barrier to stop the optimizer from moving code or assume live
- * register values. This is gcc specific, the version is more or less
- * arbitrary, might work with older compilers.
- */
-#if __GNUC_PREREQ(2, 95)
-#define	__insn_barrier()	__asm __volatile("":::"memory")
-#else
-#define	__insn_barrier()	/* */
-#endif
-
-/*
  * GNU C version 2.96 adds explicit branch prediction so that
  * the CPU back-end can hint the processor and also so that
  * code blocks can be reordered such that the predicted path
@@ -304,43 +204,19 @@
  *	  basic block reordering that this affects can often generate
  *	  larger code.
  */
-#if __GNUC_PREREQ(2, 96)
 #define	__predict_true(exp)	__builtin_expect((exp) != 0, 1)
 #define	__predict_false(exp)	__builtin_expect((exp) != 0, 0)
-#else
-#define	__predict_true(exp)	(exp)
-#define	__predict_false(exp)	(exp)
-#endif
 
-#if __GNUC_PREREQ(2, 96)
 #define __noreturn    __attribute__((__noreturn__))
 #define __mallocfunc  __attribute__((malloc))
 #define __purefunc    __attribute__((pure))
-#else
-#define __noreturn
-#define __mallocfunc
-#define __purefunc
-#endif
 
-#if __GNUC_PREREQ(3, 1)
 #define __always_inline __attribute__((__always_inline__))
-#else
-#define __always_inline
-#endif
 
-#if __GNUC_PREREQ(3, 4)
 #define __wur __attribute__((__warn_unused_result__))
-#else
-#define __wur
-#endif
 
-#if __GNUC_PREREQ(4, 3)
 #define __errorattr(msg) __attribute__((__error__(msg)))
 #define __warnattr(msg) __attribute__((__warning__(msg)))
-#else
-#define __errorattr(msg)
-#define __warnattr(msg)
-#endif
 
 #define __errordecl(name, msg) extern void name(void) __errorattr(msg)
 
@@ -540,19 +416,14 @@
  * http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html for details.
  */
 #if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
-#define __BIONIC_FORTIFY 1
-#if _FORTIFY_SOURCE == 2
-#define __bos(s) __builtin_object_size((s), 1)
-#else
-#define __bos(s) __builtin_object_size((s), 0)
-#endif
-#define __bos0(s) __builtin_object_size((s), 0)
-
-#if __GNUC_PREREQ(4,3) || __has_attribute(__artificial__)
-#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__))
-#else
-#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline))
-#endif
+#  define __BIONIC_FORTIFY 1
+#  if _FORTIFY_SOURCE == 2
+#    define __bos(s) __builtin_object_size((s), 1)
+#  else
+#    define __bos(s) __builtin_object_size((s), 0)
+#  endif
+#  define __bos0(s) __builtin_object_size((s), 0)
+#  define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__))
 #endif
 #define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
 
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 1b6853e..773d22f 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -64,6 +64,8 @@
     # The kernel's SIGRTMIN/SIGRTMAX are absolute limits; userspace steals a few.
     "SIGRTMIN": "__SIGRTMIN",
     "SIGRTMAX": "__SIGRTMAX",
+    # We want to support both BSD and Linux member names in struct udphdr.
+    "udphdr": "__kernel_udphdr",
     }
 
 # this is the set of known static inline functions that we want to keep
diff --git a/libc/kernel/uapi/linux/udp.h b/libc/kernel/uapi/linux/udp.h
index e1d546c..a3e9e97 100644
--- a/libc/kernel/uapi/linux/udp.h
+++ b/libc/kernel/uapi/linux/udp.h
@@ -19,7 +19,7 @@
 #ifndef _UAPI_LINUX_UDP_H
 #define _UAPI_LINUX_UDP_H
 #include <linux/types.h>
-struct udphdr {
+struct __kernel_udphdr {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
   __be16 source;
   __be16 dest;
diff --git a/tests/Android.mk b/tests/Android.mk
index 3f2fb91..e964a03 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -69,6 +69,7 @@
     math_test.cpp \
     mntent_test.cpp \
     netdb_test.cpp \
+    netinet_udp_test.cpp \
     pthread_test.cpp \
     pty_test.cpp \
     regex_test.cpp \
@@ -300,7 +301,6 @@
 
 bionic-unit-tests_c_includes := \
     bionic/libc \
-    $(call include-path-for, libpagemap) \
 
 bionic-unit-tests_shared_libraries_target := \
     libdl \
diff --git a/tests/netinet_udp_test.cpp b/tests/netinet_udp_test.cpp
new file mode 100644
index 0000000..661458e
--- /dev/null
+++ b/tests/netinet_udp_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <netinet/udp.h>
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+  #define UDPHDR_USES_ANON_UNION
+#elif defined(__GLIBC_PREREQ)
+  #if __GLIBC_PREREQ(2, 18)
+    #define UDPHDR_USES_ANON_UNION
+  #endif
+#endif
+
+TEST(netinet_udp, compat) {
+#if defined(UDPHDR_USES_ANON_UNION)
+    static_assert(offsetof(udphdr, uh_sport) == offsetof(udphdr, source), "udphdr::source");
+    static_assert(offsetof(udphdr, uh_dport) == offsetof(udphdr, dest), "udphdr::dest");
+    static_assert(offsetof(udphdr, uh_ulen) == offsetof(udphdr, len), "udphdr::len");
+    static_assert(offsetof(udphdr, uh_sum) == offsetof(udphdr, check), "udphdr::check");
+
+    udphdr u;
+    u.uh_sport = 0x1111;
+    u.uh_dport = 0x2222;
+    u.uh_ulen = 0x3333;
+    u.uh_sum = 0x4444;
+    ASSERT_EQ(0x1111, u.source);
+    ASSERT_EQ(0x2222, u.dest);
+    ASSERT_EQ(0x3333, u.len);
+    ASSERT_EQ(0x4444, u.check);
+#endif
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 3c686ef..1766762 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -27,6 +27,7 @@
 #include <sys/syscall.h>
 #include <time.h>
 #include <unistd.h>
+#include <unwind.h>
 
 #include <atomic>
 #include <regex>
@@ -40,6 +41,8 @@
 #include "BionicDeathTest.h"
 #include "ScopedSignalHandler.h"
 
+#include "utils.h"
+
 extern "C" pid_t gettid();
 
 TEST(pthread, pthread_key_create) {
@@ -1157,19 +1160,14 @@
 #if defined(__BIONIC__)
   // What does /proc/self/maps' [stack] line say?
   void* maps_stack_hi = NULL;
-  FILE* fp = fopen("/proc/self/maps", "r");
-  ASSERT_TRUE(fp != NULL);
-  char line[BUFSIZ];
-  while (fgets(line, sizeof(line), fp) != NULL) {
-    uintptr_t lo, hi;
-    char name[10];
-    sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d %10s", &lo, &hi, name);
-    if (strcmp(name, "[stack]") == 0) {
-      maps_stack_hi = reinterpret_cast<void*>(hi);
+  std::vector<map_record> maps;
+  ASSERT_TRUE(Maps::parse_maps(&maps));
+  for (auto& map : maps) {
+    if (map.pathname == "[stack]") {
+      maps_stack_hi = reinterpret_cast<void*>(map.addr_end);
       break;
     }
   }
-  fclose(fp);
 
   // The high address of the /proc/self/maps [stack] region should equal stack_base + stack_size.
   // Remember that the stack grows down (and is mapped in on demand), so the low address of the
@@ -1632,3 +1630,26 @@
   GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
 #endif
 }
+
+extern _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx, void* arg);
+
+static volatile bool signal_handler_on_altstack_done;
+
+static void SignalHandlerOnAltStack(int signo, siginfo_t*, void*) {
+  ASSERT_EQ(SIGUSR1, signo);
+  // Check if we have enough stack space for unwinding.
+  int count = 0;
+  _Unwind_Backtrace(FrameCounter, &count);
+  ASSERT_GT(count, 0);
+  // Check if we have enough stack space for logging.
+  std::string s(2048, '*');
+  GTEST_LOG_(INFO) << s;
+  signal_handler_on_altstack_done = true;
+}
+
+TEST(pthread, big_enough_signal_stack_for_64bit_arch) {
+  signal_handler_on_altstack_done = false;
+  ScopedSignalHandler handler(SIGUSR1, SignalHandlerOnAltStack, SA_SIGINFO | SA_ONSTACK);
+  kill(getpid(), SIGUSR1);
+  ASSERT_TRUE(signal_handler_on_altstack_done);
+}
diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp
index d1b3402..afd9e7f 100644
--- a/tests/stack_unwinding_test.cpp
+++ b/tests/stack_unwinding_test.cpp
@@ -34,7 +34,7 @@
 #define noinline __attribute__((__noinline__))
 #define __unused __attribute__((__unused__))
 
-static _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) {
+_Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) {
   int* count_ptr = reinterpret_cast<int*>(arg);
 
 #if SHOW_FRAME_LOCATIONS
diff --git a/tests/stubs_test.cpp b/tests/stubs_test.cpp
index 2d1bdee..c81ca58 100644
--- a/tests/stubs_test.cpp
+++ b/tests/stubs_test.cpp
@@ -122,6 +122,14 @@
   check_get_passwd("radio", 1001, TYPE_SYSTEM);
 }
 
+TEST(getpwnam, oem_id_0) {
+  check_get_passwd("oem_0", 5000, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, oem_id_999) {
+  check_get_passwd("oem_999", 5999, TYPE_SYSTEM);
+}
+
 TEST(getpwnam, app_id_nobody) {
   check_get_passwd("nobody", 9999, TYPE_SYSTEM);
 }
@@ -247,6 +255,14 @@
   check_get_group("radio", 1001);
 }
 
+TEST(getgrnam, oem_id_0) {
+  check_get_group("oem_0", 5000);
+}
+
+TEST(getgrnam, oem_id_999) {
+  check_get_group("oem_999", 5999);
+}
+
 TEST(getgrnam, app_id_nobody) {
   check_get_group("nobody", 9999);
 }
diff --git a/tests/utils.h b/tests/utils.h
index fd012a3..53cf6b6 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -38,9 +38,7 @@
 class Maps {
  public:
   static bool parse_maps(std::vector<map_record>* maps) {
-    char path[64];
-    snprintf(path, sizeof(path), "/proc/self/task/%d/maps", getpid());
-    FILE* fp = fopen(path, "re");
+    FILE* fp = fopen("/proc/self/maps", "re");
     if (fp == nullptr) {
       return false;
     }
@@ -53,11 +51,11 @@
     while (fgets(line, sizeof(line), fp) != nullptr) {
       map_record record;
       uint32_t dev_major, dev_minor;
-      char pathstr[BUFSIZ];
+      int path_offset;
       char prot[5]; // sizeof("rwxp")
-      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %s",
+      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %n",
             &record.addr_start, &record.addr_end, prot, &record.offset,
-            &dev_major, &dev_minor, &record.inode, pathstr) == 8) {
+            &dev_major, &dev_minor, &record.inode, &path_offset) == 7) {
         record.perms = 0;
         if (prot[0] == 'r') {
           record.perms |= PROT_READ;
@@ -72,7 +70,10 @@
         // TODO: parse shared/private?
 
         record.device = makedev(dev_major, dev_minor);
-        record.pathname = pathstr;
+        record.pathname = line + path_offset;
+        if (!record.pathname.empty() && record.pathname.back() == '\n') {
+          record.pathname.pop_back();
+        }
         maps->push_back(record);
       }
     }