Merge "Fix mma build: 'cd bionic && mma' case"
diff --git a/libc/bionic/__fgets_chk.cpp b/libc/bionic/__fgets_chk.cpp
index c09f6c5..75e4ca0 100644
--- a/libc/bionic/__fgets_chk.cpp
+++ b/libc/bionic/__fgets_chk.cpp
@@ -43,8 +43,8 @@
  * This fgets check is called if _FORTIFY_SOURCE is defined and
  * greater than 0.
  */
-extern "C" char* __fgets_chk(char* dest, int supplied_size,
-                             FILE* stream, size_t dest_len_from_compiler) {
+char* __fgets_chk(char* dest, int supplied_size, FILE* stream,
+                  size_t dest_len_from_compiler) {
   if (supplied_size < 0) {
     __fortify_chk_fail("fgets: buffer size < 0", 0);
   }
diff --git a/libc/bionic/__recvfrom_chk.cpp b/libc/bionic/__recvfrom_chk.cpp
index 48baa8e..9c894b0 100644
--- a/libc/bionic/__recvfrom_chk.cpp
+++ b/libc/bionic/__recvfrom_chk.cpp
@@ -32,9 +32,9 @@
 #include <sys/socket.h>
 #include "private/libc_logging.h"
 
-extern "C"
-ssize_t __recvfrom_chk(int socket, void* buf, size_t len, size_t buflen, unsigned int flags,
-                       const struct sockaddr* src_addr, socklen_t* addrlen) {
+ssize_t __recvfrom_chk(int socket, void* buf, size_t len, size_t buflen,
+                       int flags, const struct sockaddr* src_addr,
+                       socklen_t* addrlen) {
   if (__predict_false(len > buflen)) {
     __fortify_chk_fail("recvfrom: prevented write past end of buffer", 0);
   }
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index c23eb75..dabfea0 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -86,11 +86,6 @@
 
 
 int sem_init(sem_t* sem, int pshared, unsigned int value) {
-  if (sem == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
   // Ensure that 'value' can be stored in the semaphore.
   if (value > SEM_VALUE_MAX) {
     errno = EINVAL;
@@ -104,11 +99,7 @@
   return 0;
 }
 
-int sem_destroy(sem_t* sem) {
-  if (sem == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
+int sem_destroy(sem_t*) {
   return 0;
 }
 
@@ -205,11 +196,6 @@
 }
 
 int sem_wait(sem_t* sem) {
-  if (sem == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
   uint32_t shared = SEM_GET_SHARED(sem);
 
   while (true) {
@@ -223,11 +209,6 @@
 }
 
 int sem_timedwait(sem_t* sem, const timespec* abs_timeout) {
-  if (sem == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
   // POSIX says we need to try to decrement the semaphore
   // before checking the timeout value. Note that if the
   // value is currently 0, __sem_trydec() does nothing.
@@ -271,10 +252,6 @@
 }
 
 int sem_post(sem_t* sem) {
-  if (sem == NULL) {
-    return EINVAL;
-  }
-
   uint32_t shared = SEM_GET_SHARED(sem);
 
   ANDROID_MEMBAR_FULL();
@@ -292,11 +269,6 @@
 }
 
 int sem_trywait(sem_t* sem) {
-  if (sem == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
   if (__sem_trydec(&sem->count) > 0) {
     ANDROID_MEMBAR_FULL();
     return 0;
@@ -307,11 +279,6 @@
 }
 
 int sem_getvalue(sem_t* sem, int* sval) {
-  if (sem == NULL || sval == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
   int val = SEMCOUNT_TO_VALUE(sem->count);
   if (val < 0) {
     val = 0;
diff --git a/libc/bionic/time64.c b/libc/bionic/time64.c
index 95dfab5..da38bf3 100644
--- a/libc/bionic/time64.c
+++ b/libc/bionic/time64.c
@@ -748,10 +748,24 @@
 char *asctime64_r( const struct TM* date, char *result ) {
     /* I figure everything else can be displayed, even hour 25, but if
        these are out of range we walk off the name arrays */
-    if( !valid_tm_wday(date) || !valid_tm_mon(date) )
+    if (!valid_tm_wday(date) || !valid_tm_mon(date)) {
         return NULL;
+    }
 
-    sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+    /* Docs state this function does not support years beyond 9999. */
+    if (1900 + date->tm_year > 9999) {
+        return NULL;
+    }
+
+    /*
+     * The IBM docs for this function state that the result buffer can be
+     * assumed to be at least 26 bytes wide. The docs also state that this is
+     * only valid for years <= 9999, so we know this format string will not
+     * print more than that many characters.
+     *
+     * http://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/asctimer.htm
+     */
+    snprintf(result, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
         wday_name[date->tm_wday],
         mon_name[date->tm_mon],
         date->tm_mday, date->tm_hour,
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index f57c320..1089788 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -75,8 +75,6 @@
 extern int unlinkat(int, const char*, int);
 extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int);
 
-#if defined(__BIONIC_FORTIFY)
-
 extern int __open_2(const char*, int);
 extern int __open_real(const char*, int, ...) __RENAME(open);
 extern int __openat_2(int, const char*, int);
@@ -84,6 +82,8 @@
 __errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode");
 __errordecl(__creat_too_many_args, "too many arguments");
 
+#if defined(__BIONIC_FORTIFY)
+
 #if !defined(__clang__)
 
 __BIONIC_FORTIFY_INLINE
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 594d231..a7ec615 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -55,6 +55,8 @@
 #define __need_NULL
 #include <stddef.h>
 
+__BEGIN_DECLS
+
 #define	_FSTDIO			/* Define for new stdio with functions. */
 
 typedef off_t fpos_t;		/* stdio file position type */
@@ -144,9 +146,7 @@
 	fpos_t	_offset;	/* current lseek offset */
 } FILE;
 
-__BEGIN_DECLS
 extern FILE __sF[];
-__END_DECLS
 
 #define	__SLBF	0x0001		/* line buffered */
 #define	__SNBF	0x0002		/* unbuffered */
@@ -216,7 +216,6 @@
 /*
  * Functions defined in ANSI C standard.
  */
-__BEGIN_DECLS
 void	 clearerr(FILE *);
 int	 fclose(FILE *);
 int	 feof(FILE *);
@@ -304,16 +303,12 @@
 		__scanflike(2, 0);
 #endif /* __ISO_C_VISIBLE >= 1999 || __BSD_VISIBLE */
 
-__END_DECLS
-
-
 /*
  * Functions defined in POSIX 1003.1.
  */
 #if __BSD_VISIBLE || __POSIX_VISIBLE || __XPG_VISIBLE
 #define	L_ctermid	1024	/* size for ctermid(); PATH_MAX */
 
-__BEGIN_DECLS
 FILE	*fdopen(int, const char *);
 int	 fileno(FILE *);
 
@@ -342,15 +337,12 @@
 FILE* open_memstream(char**, size_t*);
 #endif /* __POSIX_VISIBLE >= 200809 */
 
-__END_DECLS
-
 #endif /* __BSD_VISIBLE || __POSIX_VISIBLE || __XPG_VISIBLE */
 
 /*
  * Routines that are purely local.
  */
 #if __BSD_VISIBLE
-__BEGIN_DECLS
 int	 asprintf(char ** __restrict, const char * __restrict, ...)
 		__printflike(2, 3);
 char	*fgetln(FILE * __restrict, size_t * __restrict);
@@ -365,25 +357,25 @@
 int feof_unlocked(FILE*);
 int ferror_unlocked(FILE*);
 
-__END_DECLS
-
 /*
  * Stdio function-access interface.
  */
-__BEGIN_DECLS
 FILE	*funopen(const void *,
 		int (*)(void *, char *, int),
 		int (*)(void *, const char *, int),
 		fpos_t (*)(void *, fpos_t, int),
 		int (*)(void *));
-__END_DECLS
+
 #define	fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
 #define	fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
 #endif /* __BSD_VISIBLE */
 
-#if defined(__BIONIC_FORTIFY)
+extern char* __fgets_chk(char*, int, FILE*, size_t);
+extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets);
+__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
+__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
 
-__BEGIN_DECLS
+#if defined(__BIONIC_FORTIFY)
 
 __BIONIC_FORTIFY_INLINE
 __printflike(3, 0)
@@ -429,11 +421,6 @@
 }
 #endif
 
-extern char* __fgets_chk(char*, int, FILE*, size_t);
-extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets);
-__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
-__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
-
 #if !defined(__clang__)
 
 __BIONIC_FORTIFY_INLINE
@@ -468,8 +455,8 @@
 
 #endif /* !defined(__clang__) */
 
-__END_DECLS
-
 #endif /* defined(__BIONIC_FORTIFY) */
 
+__END_DECLS
+
 #endif /* _STDIO_H_ */
diff --git a/libc/include/string.h b/libc/include/string.h
index fb24808..611c31a 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -111,6 +111,13 @@
 #define __bionic_using_gnu_basename
 #endif
 
+extern char* __stpncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t);
+extern char* __strncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t);
+extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy);
+extern size_t __strlcpy_chk(char *, const char *, size_t, size_t);
+extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat);
+extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t);
+
 #if defined(__BIONIC_FORTIFY)
 
 __BIONIC_FORTIFY_INLINE
@@ -133,8 +140,6 @@
     return __builtin___strcpy_chk(dest, src, __bos(dest));
 }
 
-extern char* __stpncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t);
-
 __BIONIC_FORTIFY_INLINE
 char* stpncpy(char* __restrict dest, const char* __restrict src, size_t n) {
     size_t bos_dest = __bos(dest);
@@ -156,8 +161,6 @@
     return __stpncpy_chk2(dest, src, n, bos_dest, bos_src);
 }
 
-extern char* __strncpy_chk2(char* __restrict, const char* __restrict, size_t, size_t, size_t);
-
 __BIONIC_FORTIFY_INLINE
 char* strncpy(char* __restrict dest, const char* __restrict src, size_t n) {
     size_t bos_dest = __bos(dest);
@@ -194,9 +197,6 @@
     return __builtin___memset_chk(s, c, n, __bos0(s));
 }
 
-extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy);
-extern size_t __strlcpy_chk(char *, const char *, size_t, size_t);
-
 __BIONIC_FORTIFY_INLINE
 size_t strlcpy(char* __restrict dest, const char* __restrict src, size_t size) {
     size_t bos = __bos(dest);
@@ -217,9 +217,6 @@
     return __strlcpy_chk(dest, src, size, bos);
 }
 
-extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat);
-extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t);
-
 
 __BIONIC_FORTIFY_INLINE
 size_t strlcat(char* __restrict dest, const char* __restrict src, size_t size) {
diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h
index 4ddcb6a..32c1206 100644
--- a/libc/include/sys/select.h
+++ b/libc/include/sys/select.h
@@ -51,10 +51,11 @@
 
 #define FD_ZERO(set) (memset(set, 0, sizeof(*(fd_set*)(set))))
 
-#if defined(__BIONIC_FORTIFY)
 extern void __FD_CLR_chk(int, fd_set*, size_t);
 extern void __FD_SET_chk(int, fd_set*, size_t);
 extern int  __FD_ISSET_chk(int, fd_set*, size_t);
+
+#if defined(__BIONIC_FORTIFY)
 #define FD_CLR(fd, set) __FD_CLR_chk(fd, set, __bos(set))
 #define FD_SET(fd, set) __FD_SET_chk(fd, set, __bos(set))
 #define FD_ISSET(fd, set) __FD_ISSET_chk(fd, set, __bos(set))
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index a8840ff..43d1586 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -291,11 +291,12 @@
 __socketcall ssize_t sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t);
 __socketcall ssize_t recvfrom(int, void*, size_t, int, const struct sockaddr*, socklen_t*);
 
-#if defined(__BIONIC_FORTIFY)
 __errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer");
 extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, const struct sockaddr*, socklen_t*);
 extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) __RENAME(recvfrom);
 
+#if defined(__BIONIC_FORTIFY)
+
 __BIONIC_FORTIFY_INLINE
 ssize_t recvfrom(int fd, void* buf, size_t len, int flags, const struct sockaddr* src_addr, socklen_t* addr_len) {
   size_t bos = __bos0(buf);
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index b56ffa4..77d7cac 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -160,12 +160,12 @@
 extern int mknod(const char*, mode_t, dev_t);
 extern mode_t umask(mode_t);
 
-#if defined(__BIONIC_FORTIFY)
-
 extern mode_t __umask_chk(mode_t);
 extern mode_t __umask_real(mode_t) __RENAME(umask);
 __errordecl(__umask_invalid_mode, "umask called with invalid mode");
 
+#if defined(__BIONIC_FORTIFY)
+
 __BIONIC_FORTIFY_INLINE
 mode_t umask(mode_t mode) {
 #if !defined(__clang__)
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 475ee1af..deac92b 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -221,12 +221,13 @@
     } while (_rc == -1 && errno == EINTR); \
     _rc; })
 
-#if defined(__BIONIC_FORTIFY)
 extern ssize_t __read_chk(int, void*, size_t, size_t);
 __errordecl(__read_dest_size_error, "read called with size bigger than destination");
 __errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
 extern ssize_t __read_real(int, void*, size_t) __RENAME(read);
 
+#if defined(__BIONIC_FORTIFY)
+
 __BIONIC_FORTIFY_INLINE
 ssize_t read(int fd, void* buf, size_t count) {
     size_t bos = __bos0(buf);
diff --git a/tests/Android.mk b/tests/Android.mk
index 9759c71..f30a4a8 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -342,7 +342,7 @@
 LOCAL_CLANG := false
 LOCAL_MODULE := bionic-compile-time-tests-g++
 LOCAL_CXXFLAGS := -Wall
-LOCAL_SRC_FILES :=
+LOCAL_SRC_FILES := fortify_sprintf_warnings.cpp
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -359,6 +359,8 @@
 LOCAL_CLANG := true
 LOCAL_MODULE := bionic-compile-time-tests-clang++
 LOCAL_CXXFLAGS := -Wall
+# FileCheck will error if there aren't any CLANG: lines in the file, but there
+# don't appear to be any cases where clang _does_ emit warnings for sn?printf :(
 LOCAL_SRC_FILES :=
 include $(BUILD_STATIC_LIBRARY)
 
@@ -399,8 +401,8 @@
 	  sudo mkdir -p -m 0777 /system/bin; \
 	fi
 	mkdir -p $(TARGET_OUT_DATA)/local/tmp
-	cp $(TARGET_OUT_EXECUTABLES)/$(LINKER) /system/bin
-	cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin
+	ln -fs `realpath $(TARGET_OUT_EXECUTABLES)/$(LINKER)` /system/bin
+	ln -fs `realpath $(TARGET_OUT_EXECUTABLES)/sh` /system/bin
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
 	ANDROID_ROOT=$(TARGET_OUT) \
 	LD_LIBRARY_PATH=$(TARGET_OUT_SHARED_LIBRARIES) \
@@ -415,8 +417,8 @@
 	  sudo mkdir -p -m 0777 /system/bin; \
 	fi
 	mkdir -p $(TARGET_OUT_DATA)/local/tmp
-	cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin
-	cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin
+	ln -fs `realpath $(TARGET_OUT_EXECUTABLES)/linker` /system/bin
+	ln -fs `realpath $(TARGET_OUT_EXECUTABLES)/sh` /system/bin
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
 	ANDROID_ROOT=$(TARGET_OUT) \
 	LD_LIBRARY_PATH=$(2ND_TARGET_OUT_SHARED_LIBRARIES) \
diff --git a/tests/fortify_sprintf_warnings.cpp b/tests/fortify_sprintf_warnings.cpp
new file mode 100644
index 0000000..3a2d3c4
--- /dev/null
+++ b/tests/fortify_sprintf_warnings.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#undef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 2
+#include <stdio.h>
+
+void test_sprintf() {
+  char buf[4];
+
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: warning: call to int __builtin___sprintf_chk(char*, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
+  // clang should emit a warning, but doesn't
+  sprintf(buf, "foobar"); // NOLINT(runtime/printf)
+
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: warning: call to int __builtin___sprintf_chk(char*, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
+  // clang should emit a warning, but doesn't
+  sprintf(buf, "%s", "foobar"); // NOLINT(runtime/printf)
+}
+
+void test_snprintf() {
+  char buf[4];
+
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
+  // clang should emit a warning, but doesn't
+  snprintf(buf, 5, "foobar"); // NOLINT(runtime/printf)
+
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
+  // clang should emit a warning, but doesn't
+  snprintf(buf, 5, "%s", "foobar"); // NOLINT(runtime/printf)
+
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
+  // clang should emit a warning, but doesn't
+  snprintf(buf, 5, " %s ", "foobar"); // NOLINT(runtime/printf)
+
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
+  // clang should emit a warning, but doesn't
+  snprintf(buf, 5, "%d", 100000); // NOLINT(runtime/printf)
+}