Merge "Add per UID interface support to resolv cache"
diff --git a/libc/arch-arm/bionic/abort_arm.S b/libc/arch-arm/bionic/abort_arm.S
index 51b0871..e1ab86b 100644
--- a/libc/arch-arm/bionic/abort_arm.S
+++ b/libc/arch-arm/bionic/abort_arm.S
@@ -38,5 +38,5 @@
 ENTRY(abort)
     .save   {r3, r14}
     stmfd   sp!, {r3, r14}
-    blx     PIC_SYM(_C_LABEL(__libc_android_abort), PLT)
+    bl      PIC_SYM(_C_LABEL(__libc_android_abort), PLT)
 END(abort)
diff --git a/libc/arch-x86/string/strcat.S b/libc/arch-x86/string/strcat.S
deleted file mode 100644
index c75f38a..0000000
--- a/libc/arch-x86/string/strcat.S
+++ /dev/null
@@ -1,74 +0,0 @@
-/*	$OpenBSD: strcat.S,v 1.8 2005/08/07 11:30:38 espie Exp $ */
-/*
- * Written by J.T. Conklin <jtc@netbsd.org>.
- * Public domain.
- */
-
-#include <machine/asm.h>
-
-#if defined(APIWARN)
-#APP
-	.section .gnu.warning.strcat
-	.ascii "warning: strcat() is almost always misused, please use strlcat()"
-#NO_APP
-#endif
-
-/*
- * NOTE: I've unrolled the loop eight times: large enough to make a
- * significant difference, and small enough not to totally trash the
- * cache.
- */
-
-ENTRY(strcat)
-	pushl	%edi			/* save edi */
-	movl	8(%esp),%edi		/* dst address */
-	movl	12(%esp),%edx		/* src address */
-	pushl	%edi			/* push destination address */
-
-	cld				/* set search forward */
-	xorl	%eax,%eax		/* set search for null terminator */
-	movl	$-1,%ecx		/* set search for lots of characters */
-	repne				/* search! */
-	scasb
-
-	leal	-1(%edi),%ecx		/* correct dst address */
-
-	.align 2,0x90
-L1:	movb	(%edx),%al		/* unroll loop, but not too much */
-	movb	%al,(%ecx)
-	testb	%al,%al
-	jz	L2
-	movb	1(%edx),%al
-	movb	%al,1(%ecx)
-	testb	%al,%al
-	jz	L2
-	movb	2(%edx),%al
-	movb	%al,2(%ecx)
-	testb	%al,%al
-	jz	L2
-	movb	3(%edx),%al
-	movb	%al,3(%ecx)
-	testb	%al,%al
-	jz	L2
-	movb	4(%edx),%al
-	movb	%al,4(%ecx)
-	testb	%al,%al
-	jz	L2
-	movb	5(%edx),%al
-	movb	%al,5(%ecx)
-	testb	%al,%al
-	jz	L2
-	movb	6(%edx),%al
-	movb	%al,6(%ecx)
-	testb	%al,%al
-	jz	L2
-	movb	7(%edx),%al
-	movb	%al,7(%ecx)
-	addl	$8,%edx
-	addl	$8,%ecx
-	testb	%al,%al
-	jnz	L1
-L2:	popl	%eax			/* pop destination address */
-	popl	%edi			/* restore edi */
-	ret
-END(strcat)
diff --git a/libc/bionic/__strcat_chk.cpp b/libc/bionic/__strcat_chk.cpp
index fb46e0d..e0b3259 100644
--- a/libc/bionic/__strcat_chk.cpp
+++ b/libc/bionic/__strcat_chk.cpp
@@ -29,7 +29,6 @@
 #include <string.h>
 #include <stdlib.h>
 #include "libc_logging.h"
-#include <safe_iop.h>
 
 /*
  * Runtime implementation of __builtin____strcat_chk.
@@ -42,22 +41,24 @@
  * This strcat check is called if _FORTIFY_SOURCE is defined and
  * greater than 0.
  */
-extern "C" char *__strcat_chk (char *dest, const char *src, size_t dest_buf_size) {
-    // TODO: optimize so we don't scan src/dest twice.
-    size_t src_len  = strlen(src);
-    size_t dest_len = strlen(dest);
-    size_t sum;
+extern "C" char* __strcat_chk(
+        char* __restrict dest,
+        const char* __restrict src,
+        size_t dest_buf_size)
+{
+    char* save = dest;
+    size_t dest_len = __strlen_chk(dest, dest_buf_size);
 
-    // sum = src_len + dest_len + 1 (with overflow protection)
-    if (!safe_add3(&sum, src_len, dest_len, 1U)) {
-        __fortify_chk_fail("strcat integer overflow",
-                             BIONIC_EVENT_STRCAT_INTEGER_OVERFLOW);
+    dest += dest_len;
+    dest_buf_size -= dest_len;
+
+    while ((*dest++ = *src++) != '\0') {
+        dest_buf_size--;
+        if (__predict_false(dest_buf_size == 0)) {
+            __fortify_chk_fail("strcat buffer overflow",
+                               BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW);
+        }
     }
 
-    if (sum > dest_buf_size) {
-        __fortify_chk_fail("strcat buffer overflow",
-                             BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW);
-    }
-
-    return strcat(dest, src);
+    return save;
 }
diff --git a/libc/bionic/__strncat_chk.cpp b/libc/bionic/__strncat_chk.cpp
index ab28541..f54d838 100644
--- a/libc/bionic/__strncat_chk.cpp
+++ b/libc/bionic/__strncat_chk.cpp
@@ -29,7 +29,6 @@
 #include <string.h>
 #include <stdlib.h>
 #include "libc_logging.h"
-#include <safe_iop.h>
 
 /*
  * Runtime implementation of __builtin____strncat_chk.
@@ -42,27 +41,33 @@
  * This strncat check is called if _FORTIFY_SOURCE is defined and
  * greater than 0.
  */
-extern "C" char *__strncat_chk (char *dest, const char *src,
-              size_t len, size_t dest_buf_size)
+extern "C" char *__strncat_chk(
+        char* __restrict dest,
+        const char* __restrict src,
+        size_t len, size_t dest_buf_size)
 {
-    // TODO: optimize so we don't scan src/dest twice.
-    size_t dest_len = strlen(dest);
-    size_t src_len = strlen(src);
-    if (src_len > len) {
-        src_len = len;
+    if (len == 0) {
+        return dest;
     }
 
-    size_t sum;
-    // sum = src_len + dest_len + 1 (with overflow protection)
-    if (!safe_add3(&sum, src_len, dest_len, 1U)) {
-        __fortify_chk_fail("strncat integer overflow",
-                             BIONIC_EVENT_STRNCAT_INTEGER_OVERFLOW);
+    size_t dest_len = __strlen_chk(dest, dest_buf_size);
+    char *d = dest + dest_len;
+    dest_buf_size -= dest_len;
+
+    while (*src != '\0') {
+        *d++ = *src++;
+        len--; dest_buf_size--;
+
+        if (__predict_false(dest_buf_size == 0)) {
+            __fortify_chk_fail("strncat buffer overflow",
+                               BIONIC_EVENT_STRNCAT_BUFFER_OVERFLOW);
+        }
+
+        if (len == 0) {
+            break;
+        }
     }
 
-    if (sum > dest_buf_size) {
-        __fortify_chk_fail("strncat buffer overflow",
-                             BIONIC_EVENT_STRNCAT_BUFFER_OVERFLOW);
-    }
-
-    return strncat(dest, src, len);
+    *d = '\0';
+    return dest;
 }
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index f6fa83c..9cc84c3 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -190,7 +190,7 @@
     return dlmallinfo();
 }
 
-extern "C" size_t malloc_usable_size(void* mem) {
+extern "C" size_t malloc_usable_size(const void* mem) {
     return dlmalloc_usable_size(mem);
 }
 
diff --git a/libc/bionic/mmap.c b/libc/bionic/mmap.c
index 40a6538..e097086 100644
--- a/libc/bionic/mmap.c
+++ b/libc/bionic/mmap.c
@@ -34,10 +34,17 @@
 #define  MMAP2_SHIFT  12
 void* mmap(void *addr, size_t size, int prot, int flags, int fd, long offset)
 {
+    void *ret;
+
     if (offset & ((1UL << MMAP2_SHIFT)-1)) {
         errno = EINVAL;
         return MAP_FAILED;
     }
 
-    return __mmap2(addr, size, prot, flags, fd, (size_t)offset >> MMAP2_SHIFT);
+    ret = __mmap2(addr, size, prot, flags, fd, (size_t)offset >> MMAP2_SHIFT);
+
+    if (ret && (flags & (MAP_PRIVATE | MAP_ANONYMOUS)))
+	    madvise(ret, size, MADV_MERGEABLE);
+
+    return ret;
 }
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 0eb0e0a..316a14a 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -30,6 +30,7 @@
 
 #include <pthread.h>
 #include <stdbool.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 8875e54..eaedc49 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -33,7 +33,7 @@
 extern void free(void* p);
 
 extern void* memalign(size_t alignment, size_t byte_count) __mallocfunc __wur;
-extern size_t malloc_usable_size(void* p);
+extern size_t malloc_usable_size(const void* p);
 
 extern void* valloc(size_t byte_count) __mallocfunc __wur;
 extern void* pvalloc(size_t byte_count) __mallocfunc __wur;
diff --git a/libc/include/mntent.h b/libc/include/mntent.h
index b83da1f..8b87f71 100644
--- a/libc/include/mntent.h
+++ b/libc/include/mntent.h
@@ -29,6 +29,7 @@
 #define _MNTENT_H_
 
 #include <stdio.h>
+#include <sys/cdefs.h>
 
 #define MNTTYPE_IGNORE "ignore"
 
diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h
index c5b964e..bf3b498 100644
--- a/libc/include/netinet/in.h
+++ b/libc/include/netinet/in.h
@@ -29,11 +29,13 @@
 #define _NETINET_IN_H_
 
 #include <endian.h>
+#include <netinet/in6.h>
+#include <sys/cdefs.h>
 #include <sys/socket.h>
+
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/ipv6.h>
-#include <netinet/in6.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 8c9b170..15d2d3a 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -59,32 +59,32 @@
 
 static __inline__ int sigismember(const sigset_t* set, int signum) {
   int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
+  const unsigned long* local_set = (const unsigned long*) set;
   if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
     errno = EINVAL;
     return -1;
   }
-  const unsigned long* local_set = (const unsigned long*) set;
   return (int) ((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1);
 }
 
 static __inline__ int sigaddset(sigset_t* set, int signum) {
   int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
+  unsigned long* local_set = (unsigned long*) set;
   if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
     errno = EINVAL;
     return -1;
   }
-  unsigned long* local_set = (unsigned long*) set;
   local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
   return 0;
 }
 
 static __inline__ int sigdelset(sigset_t* set, int signum) {
   int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
+  unsigned long* local_set = (unsigned long*) set;
   if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
     errno = EINVAL;
     return -1;
   }
-  unsigned long* local_set = (unsigned long*) set;
   local_set[bit / LONG_BIT] &= ~(1UL << (bit % LONG_BIT));
   return 0;
 }
diff --git a/libc/include/string.h b/libc/include/string.h
index f8c573c..1691b16 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -49,6 +49,7 @@
 extern char*  strrchr(const char *, int) __purefunc;
 
 extern size_t strlen(const char *) __purefunc;
+extern size_t __strlen_chk(const char *, size_t);
 extern int    strcmp(const char *, const char *) __purefunc;
 extern char*  strcpy(char* __restrict, const char* __restrict);
 extern char*  strcat(char* __restrict, const char* __restrict);
@@ -207,8 +208,6 @@
     return __strlcat_chk(dest, src, size, bos);
 }
 
-extern size_t __strlen_chk(const char *, size_t);
-
 __BIONIC_FORTIFY_INLINE
 size_t strlen(const char *s) {
     size_t bos = __bos(s);
diff --git a/libc/include/sys/auxv.h b/libc/include/sys/auxv.h
index 918442f..0d753c3 100644
--- a/libc/include/sys/auxv.h
+++ b/libc/include/sys/auxv.h
@@ -29,6 +29,7 @@
 #define _SYS_AUXV_H_
 
 #include <linux/auxvec.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/include/sys/personality.h b/libc/include/sys/personality.h
index 7772550..8a023f9 100644
--- a/libc/include/sys/personality.h
+++ b/libc/include/sys/personality.h
@@ -29,6 +29,7 @@
 #ifndef _SYS_PERSONALITY_H_
 #define _SYS_PERSONALITY_H_
 
+#include <sys/cdefs.h>
 #include <linux/personality.h>
 
 __BEGIN_DECLS
diff --git a/libc/include/sys/signalfd.h b/libc/include/sys/signalfd.h
index c03a0e9..a249d65 100644
--- a/libc/include/sys/signalfd.h
+++ b/libc/include/sys/signalfd.h
@@ -29,8 +29,9 @@
 #ifndef _SYS_SIGNALFD_H_
 #define _SYS_SIGNALFD_H_
 
-#include <signal.h>
 #include <linux/signalfd.h>
+#include <signal.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/include/sys/timeb.h b/libc/include/sys/timeb.h
index f2cc39c..cf6f255 100644
--- a/libc/include/sys/timeb.h
+++ b/libc/include/sys/timeb.h
@@ -28,6 +28,7 @@
 #ifndef _SYS_TIMEB_H
 #define _SYS_TIMEB_H
 
+#include <sys/cdefs.h>
 #include <sys/time.h>
 
 __BEGIN_DECLS
diff --git a/libc/netbsd/net/reentrant.h b/libc/netbsd/net/reentrant.h
index 15507eb..60bff08 100644
--- a/libc/netbsd/net/reentrant.h
+++ b/libc/netbsd/net/reentrant.h
@@ -102,6 +102,7 @@
 
 #include <pthread.h>
 #include <signal.h>
+#include <sys/cdefs.h>
 
 #define	mutex_t			pthread_mutex_t
 #define	MUTEX_INITIALIZER	PTHREAD_MUTEX_INITIALIZER
diff --git a/libc/private/bionic_auxv.h b/libc/private/bionic_auxv.h
index 69d15b6..23b2e37 100644
--- a/libc/private/bionic_auxv.h
+++ b/libc/private/bionic_auxv.h
@@ -29,6 +29,7 @@
 #define _PRIVATE_BIONIC_AUXV_H_
 
 #include <elf.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/private/bionic_futex.h b/libc/private/bionic_futex.h
index 6c7fdbe..69658b1 100644
--- a/libc/private/bionic_futex.h
+++ b/libc/private/bionic_futex.h
@@ -29,6 +29,7 @@
 #define _BIONIC_FUTEX_H
 
 #include <linux/futex.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/private/bionic_time.h b/libc/private/bionic_time.h
index 464ab0f..7c80f59 100644
--- a/libc/private/bionic_time.h
+++ b/libc/private/bionic_time.h
@@ -29,6 +29,7 @@
 #define _BIONIC_TIME_H
 
 #include <time.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/private/libc_logging.h b/libc/private/libc_logging.h
index c6e1765..e62ddf2 100644
--- a/libc/private/libc_logging.h
+++ b/libc/private/libc_logging.h
@@ -45,9 +45,6 @@
   BIONIC_EVENT_MEMSET_BUFFER_OVERFLOW = 80125,
   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW = 80130,
 
-  BIONIC_EVENT_STRCAT_INTEGER_OVERFLOW = 80200,
-  BIONIC_EVENT_STRNCAT_INTEGER_OVERFLOW = 80205,
-
   BIONIC_EVENT_RESOLVER_OLD_RESPONSE = 80300,
   BIONIC_EVENT_RESOLVER_WRONG_SERVER = 80305,
   BIONIC_EVENT_RESOLVER_WRONG_QUERY = 80310,
diff --git a/libc/private/resolv_private.h b/libc/private/resolv_private.h
index 1c3c1a2..0e799ca 100644
--- a/libc/private/resolv_private.h
+++ b/libc/private/resolv_private.h
@@ -54,6 +54,8 @@
 #ifndef _RESOLV_PRIVATE_H_
 #define	_RESOLV_PRIVATE_H_
 
+#include <sys/cdefs.h>
+
 #include <resolv.h>
 #include "resolv_static.h"
 #include <net/if.h>
diff --git a/libc/private/thread_private.h b/libc/private/thread_private.h
index c03f0ab..b19ad09 100644
--- a/libc/private/thread_private.h
+++ b/libc/private/thread_private.h
@@ -20,22 +20,6 @@
 extern int __isthreaded;
 
 /*
- * Weak symbols are used in libc so that the thread library can
- * efficiently wrap libc functions.
- * 
- * Use WEAK_NAME(n) to get a libc-private name for n (_weak_n),
- *     WEAK_ALIAS(n) to generate the weak symbol n pointing to _weak_n,
- *     WEAK_PROTOTYPE(n) to generate a prototype for _weak_n (based on n).
- */
-#define WEAK_NAME(name)		__CONCAT(_weak_,name)
-#define WEAK_ALIAS(name)	__weak_alias(name, WEAK_NAME(name))
-#ifdef __GNUC__
-#define WEAK_PROTOTYPE(name)	__typeof__(name) WEAK_NAME(name)
-#else
-#define WEAK_PROTOTYPE(name)	/* typeof() only in gcc */
-#endif
-
-/*
  * helper macro to make unique names in the thread namespace
  */
 #define __THREAD_NAME(name)	__CONCAT(_thread_tagname_,name)
@@ -52,101 +36,6 @@
 #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
 	pthread_mutex_unlock( &__THREAD_NAME(name)._private_lock )
 
-#define _THREAD_PRIVATE_KEY(name)    \
-	static struct __thread_private_tag_t  __THREAD_NAME(name) = { PTHREAD_MUTEX_INITIALIZER, -1 }
-
-extern void*  __bionic_thread_private_storage( struct __thread_private_tag_t*  ptag, void*  storage, size_t  objsize, void*  error );
-
-#define _THREAD_PRIVATE(name, storage, error)    \
-	__bionic_thread_private_storage( &__THREAD_NAME(name), &(storage),sizeof(storage), error)
-	
-#if 0
-/*
- * helper functions that exist as (weak) null functions in libc and
- * (strong) functions in the thread library.   These functions:
- *
- * _thread_tag_lock:
- *	lock the mutex associated with the given tag.   If the given
- *	tag is NULL a tag is first allocated.
- *
- * _thread_tag_unlock:
- *	unlock the mutex associated with the given tag.   If the given
- *	tag is NULL a tag is first allocated.
- *
- * _thread_tag_storage:
- *	return a pointer to per thread instance of data associated
- *	with the given tag.  If the given tag is NULL a tag is first
- *	allocated.
- */
-void	_thread_tag_lock(void **);
-void	_thread_tag_unlock(void **);
-void   *_thread_tag_storage(void **, void *, size_t, void *);
-
-/*
- * Macros used in libc to access thread mutex, keys, and per thread storage.
- * _THREAD_PRIVATE_KEY and _THREAD_PRIVATE_MUTEX are different macros for
- * historical reasons.   They do the same thing, define a static variable
- * keyed by 'name' that identifies a mutex and a key to identify per thread
- * data.
- */
-#define _THREAD_PRIVATE_KEY(name)					\
-	static void *__THREAD_NAME(name)
-#define _THREAD_PRIVATE_MUTEX(name)					\
-	static void *__THREAD_NAME(name)
-#define _THREAD_PRIVATE_MUTEX_LOCK(name)				\
-	_thread_tag_lock(&(__THREAD_NAME(name)))
-#define _THREAD_PRIVATE_MUTEX_UNLOCK(name)				\
-	_thread_tag_unlock(&(__THREAD_NAME(name)))
-#define _THREAD_PRIVATE(keyname, storage, error)			\
-	_thread_tag_storage(&(__THREAD_NAME(keyname)), &(storage),	\
-			    sizeof (storage), error)
-/*
- * Resolver code is special cased in that it uses global keys.
- */
-extern void *__THREAD_NAME(_res);
-extern void *__THREAD_NAME(_res_ext);
-extern void *__THREAD_NAME(serv_mutex);
-#endif
-
-/*
- * File descriptor locking definitions.
- */
-#define FD_READ		0x1
-#define FD_WRITE	0x2
-#define FD_RDWR		(FD_READ | FD_WRITE)
-
-struct timespec;
-int	_thread_fd_lock(int, int, struct timespec *);
-void	_thread_fd_unlock(int, int);
-
-/*
- * Macros are used in libc code for historical (debug) reasons.
- * Define them here.
- */
-#define _FD_LOCK(_fd,_type,_ts)	_thread_fd_lock(_fd, _type, _ts)
-#define _FD_UNLOCK(_fd,_type)	_thread_fd_unlock(_fd, _type)
-
-
-/*
- * malloc lock/unlock prototypes and definitions
- */
-void	_thread_malloc_init(void);
-void	_thread_malloc_lock(void);
-void	_thread_malloc_unlock(void);
-
-#define _MALLOC_LOCK()		do {					\
-					if (__isthreaded)		\
-						_thread_malloc_lock();	\
-				} while (0)
-#define _MALLOC_UNLOCK()	do {					\
-					if (__isthreaded)		\
-						_thread_malloc_unlock();\
-				} while (0)
-#define _MALLOC_LOCK_INIT()	do {					\
-					if (__isthreaded)		\
-						_thread_malloc_init();\
-				} while (0)
-
 void	_thread_atexit_lock(void);
 void	_thread_atexit_unlock(void);
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index c97b712..80dc624 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -440,17 +440,14 @@
 #endif
 
 static Elf32_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
-    Elf32_Sym* s;
     Elf32_Sym* symtab = si->symtab;
     const char* strtab = si->strtab;
-    unsigned n;
 
     TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %d",
                name, si->name, si->base, hash, hash % si->nbucket);
-    n = hash % si->nbucket;
 
-    for (n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
-        s = symtab + n;
+    for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
+        Elf32_Sym* s = symtab + n;
         if (strcmp(strtab + s->st_name, name)) continue;
 
             /* only concern ourselves with global and weak symbol definitions */
diff --git a/tests/fortify1_test.cpp b/tests/fortify1_test.cpp
index e237193..b5cf208 100644
--- a/tests/fortify1_test.cpp
+++ b/tests/fortify1_test.cpp
@@ -23,6 +23,8 @@
 #if __BIONIC__
 // We have to say "DeathTest" here so gtest knows to run this test (which exits)
 // in its own process.
+
+// multibyte target where we over fill (should fail)
 TEST(Fortify1_DeathTest, strcpy_fortified) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
   char buf[10];
@@ -31,6 +33,33 @@
   free(orig);
 }
 
+// zero sized target with "\0" source (should fail)
+TEST(Fortify1_DeathTest, strcpy2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+  free(orig);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify1_DeathTest, strcpy3_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("1");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+  free(orig);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify1_DeathTest, strcpy4_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[1];
+  char *orig = strdup("12");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+  free(orig);
+}
+
 TEST(Fortify1_DeathTest, strlen_fortified) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
   char buf[10];
@@ -60,3 +89,182 @@
   memcpy(source_buf, "12345678901234", 15);
   ASSERT_EXIT(sprintf(buf, "%s", source_buf), testing::KilledBySignal(SIGSEGV), "");
 }
+
+TEST(Fortify1_DeathTest, strncat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  size_t n = atoi("10"); // avoid compiler optimizations
+  strncpy(buf, "012345678", n);
+  ASSERT_EXIT(strncat(buf, "9", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify1_DeathTest, strncat2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  buf[0] = '\0';
+  size_t n = atoi("10"); // avoid compiler optimizations
+  ASSERT_EXIT(strncat(buf, "0123456789", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify1_DeathTest, strcat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char src[11];
+  strcpy(src, "0123456789");
+  char buf[10];
+  buf[0] = '\0';
+  ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGSEGV), "");
+}
+
+extern "C" char* __strncat_chk(char*, const char*, size_t, size_t);
+extern "C" char* __strcat_chk(char*, const char*, size_t);
+
+TEST(Fortify1, strncat) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "01234", sizeof(buf) - strlen(buf) - 1, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1, strncat2) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "0123456789", 5, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1, strncat3) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = '\0';
+  char* res = __strncat_chk(buf, "0123456789", 5, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('0',  buf[0]);
+  ASSERT_EQ('1',  buf[1]);
+  ASSERT_EQ('2',  buf[2]);
+  ASSERT_EQ('3',  buf[3]);
+  ASSERT_EQ('4',  buf[4]);
+  ASSERT_EQ('\0', buf[5]);
+  ASSERT_EQ('A',  buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1, strncat4) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[9] = '\0';
+  char* res = __strncat_chk(buf, "", 5, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('A',  buf[0]);
+  ASSERT_EQ('A',  buf[1]);
+  ASSERT_EQ('A',  buf[2]);
+  ASSERT_EQ('A',  buf[3]);
+  ASSERT_EQ('A',  buf[4]);
+  ASSERT_EQ('A',  buf[5]);
+  ASSERT_EQ('A',  buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('\0', buf[9]);
+}
+
+TEST(Fortify1, strncat5) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "01234567", 8, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
+TEST(Fortify1, strncat6) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "01234567", 9, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
+
+TEST(Fortify1, strcat) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strcat_chk(buf, "01234", sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1, strcat2) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strcat_chk(buf, "01234567", sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
diff --git a/tests/fortify2_test.cpp b/tests/fortify2_test.cpp
index ea890fe..f0c2e77 100644
--- a/tests/fortify2_test.cpp
+++ b/tests/fortify2_test.cpp
@@ -21,6 +21,8 @@
 #include <string.h>
 
 struct foo {
+  char empty[0];
+  char one[1];
   char a[10];
   char b[10];
 };
@@ -45,6 +47,36 @@
 }
 
 #if __BIONIC__
+// zero sized target with "\0" source (should fail)
+TEST(Fortify2_DeathTest, strcpy_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  char* src = strdup("");
+  ASSERT_EXIT(strcpy(myfoo.empty, src),
+              testing::KilledBySignal(SIGSEGV), "");
+  free(src);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy2_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  char* src = strdup("1");
+  ASSERT_EXIT(strcpy(myfoo.empty, src),
+              testing::KilledBySignal(SIGSEGV), "");
+  free(src);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy3_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  char* src = strdup("12");
+  ASSERT_EXIT(strcpy(myfoo.one, src),
+              testing::KilledBySignal(SIGSEGV), "");
+  free(src);
+}
+
 TEST(Fortify2_DeathTest, strchr_fortified2) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
   foo myfoo;
@@ -64,11 +96,54 @@
 }
 #endif
 
+TEST(Fortify2_DeathTest, strncat_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  size_t n = atoi("10"); // avoid compiler optimizations
+  strncpy(myfoo.a, "012345678", n);
+  ASSERT_EXIT(strncat(myfoo.a, "9", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strncat2_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  myfoo.a[0] = '\0';
+  size_t n = atoi("10"); // avoid compiler optimizations
+  ASSERT_EXIT(strncat(myfoo.a, "0123456789", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strncat3_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); // unterminated string
+  myfoo.b[0] = '\0';
+  size_t n = atoi("10"); // avoid compiler optimizations
+  ASSERT_EXIT(strncat(myfoo.b, myfoo.a, n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strcat_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char src[11];
+  strcpy(src, "0123456789");
+  foo myfoo;
+  myfoo.a[0] = '\0';
+  ASSERT_EXIT(strcat(myfoo.a, src), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strcat2_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); // unterminated string
+  myfoo.b[0] = '\0';
+  ASSERT_EXIT(strcat(myfoo.b, myfoo.a), testing::KilledBySignal(SIGSEGV), "");
+}
+
 /***********************************************************/
 /* TESTS BELOW HERE DUPLICATE TESTS FROM fortify1_test.cpp */
 /***********************************************************/
 
 #if __BIONIC__
+// multibyte target where we over fill (should fail)
 TEST(Fortify2_DeathTest, strcpy_fortified) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
   char buf[10];
@@ -77,6 +152,33 @@
   free(orig);
 }
 
+// zero sized target with "\0" source (should fail)
+TEST(Fortify2_DeathTest, strcpy2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+  free(orig);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy3_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("1");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+  free(orig);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy4_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[1];
+  char *orig = strdup("12");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+  free(orig);
+}
+
 TEST(Fortify2_DeathTest, strlen_fortified) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
   char buf[10];
@@ -106,3 +208,28 @@
   memcpy(source_buf, "12345678901234", 15);
   ASSERT_EXIT(sprintf(buf, "%s", source_buf), testing::KilledBySignal(SIGSEGV), "");
 }
+
+TEST(Fortify2_DeathTest, strncat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  size_t n = atoi("10"); // avoid compiler optimizations
+  strncpy(buf, "012345678", n);
+  ASSERT_EXIT(strncat(buf, "9", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strncat2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  buf[0] = '\0';
+  size_t n = atoi("10"); // avoid compiler optimizations
+  ASSERT_EXIT(strncat(buf, "0123456789", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strcat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char src[11];
+  strcpy(src, "0123456789");
+  char buf[10];
+  buf[0] = '\0';
+  ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGSEGV), "");
+}
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 63bfadb..91d1904 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -209,6 +209,167 @@
   }
 }
 
+// one byte target with "\0" source
+TEST(string, strcpy2) {
+  char buf[1];
+  char* orig = strdup("");
+  strcpy(buf, orig);
+  ASSERT_EQ('\0', buf[0]);
+  free(orig);
+}
+
+// multibyte target where we under fill target
+TEST(string, strcpy3) {
+  char buf[10];
+  char* orig = strdup("12345");
+  memset(buf, 'A', sizeof(buf));
+  strcpy(buf, orig);
+  ASSERT_EQ('1',  buf[0]);
+  ASSERT_EQ('2',  buf[1]);
+  ASSERT_EQ('3',  buf[2]);
+  ASSERT_EQ('4',  buf[3]);
+  ASSERT_EQ('5',  buf[4]);
+  ASSERT_EQ('\0', buf[5]);
+  ASSERT_EQ('A',  buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+  free(orig);
+}
+
+// multibyte target where we fill target exactly
+TEST(string, strcpy4) {
+  char buf[10];
+  char* orig = strdup("123456789");
+  memset(buf, 'A', sizeof(buf));
+  strcpy(buf, orig);
+  ASSERT_EQ('1',  buf[0]);
+  ASSERT_EQ('2',  buf[1]);
+  ASSERT_EQ('3',  buf[2]);
+  ASSERT_EQ('4',  buf[3]);
+  ASSERT_EQ('5',  buf[4]);
+  ASSERT_EQ('6',  buf[5]);
+  ASSERT_EQ('7',  buf[6]);
+  ASSERT_EQ('8',  buf[7]);
+  ASSERT_EQ('9',  buf[8]);
+  ASSERT_EQ('\0', buf[9]);
+  free(orig);
+}
+
+TEST(string, strcat2) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = strcat(buf, "01234");
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(string, strcat3) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = strcat(buf, "01234567");
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
+TEST(string, strncat2) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = strncat(buf, "01234", sizeof(buf) - strlen(buf) - 1);
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(string, strncat3) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = strncat(buf, "0123456789", 5);
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(string, strncat4) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = strncat(buf, "01234567", 8);
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
+TEST(string, strncat5) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = strncat(buf, "01234567", 9);
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
 TEST(string, strchr_with_0) {
   char buf[10];
   const char* s = "01234";