Merge "Bionic: Add a TLS slot for ART for Thread self"
diff --git a/libc/Android.mk b/libc/Android.mk
index 5e09cf9..0f18ca4 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -72,6 +72,7 @@
     bionic/__fgets_chk.cpp \
     bionic/__fread_chk.cpp \
     bionic/__fwrite_chk.cpp \
+    bionic/__getcwd_chk.cpp \
     bionic/__memchr_chk.cpp \
     bionic/__memmove_chk.cpp \
     bionic/__memrchr_chk.cpp \
@@ -577,10 +578,6 @@
     -D_LIBC=1 \
     -Wall -Wextra -Wunused \
 
-ifneq ($(TARGET_USES_LOGD),false)
-libc_common_cflags += -DTARGET_USES_LOGD
-endif
-
 use_clang := $(USE_CLANG_PLATFORM_BUILD)
 
 # Clang/llvm has incompatible long double (fp128) for x86_64.
diff --git a/libc/bionic/__getcwd_chk.cpp b/libc/bionic/__getcwd_chk.cpp
new file mode 100644
index 0000000..b53ab5c
--- /dev/null
+++ b/libc/bionic/__getcwd_chk.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#undef _FORTIFY_SOURCE
+
+#include <unistd.h>
+#include "private/libc_logging.h"
+
+extern char* __getcwd_chk(char* buf, size_t len, size_t buflen) {
+  if (__predict_false(len > buflen)) {
+    __fortify_chk_fail("getcwd: prevented write past end of buffer", 0);
+  }
+
+  return getcwd(buf, len);
+}
diff --git a/libc/bionic/getcwd.cpp b/libc/bionic/getcwd.cpp
index a8bbcf3..bcd6a57 100644
--- a/libc/bionic/getcwd.cpp
+++ b/libc/bionic/getcwd.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#undef _FORTIFY_SOURCE
 #include <errno.h>
 #include <malloc.h>
 #include <string.h>
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index ef57af6..2b1a8cb 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -49,16 +49,10 @@
 #include "libc_init_common.h"
 #include "pthread_internal.h"
 
+#include "private/bionic_page.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 
-// Returns the address of the page containing address 'x'.
-#define PAGE_START(x)  ((x) & PAGE_MASK)
-
-// Returns the address of the next page after address 'x', unless 'x' is
-// itself at the start of a page.
-#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
-
 extern "C" int __cxa_atexit(void (*)(void *), void *, void *);
 
 static void call_array(void(**list)()) {
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index cb0b334..2a987b9 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -448,7 +448,6 @@
   return result;
 }
 
-#ifdef TARGET_USES_LOGD
 static int __libc_open_log_socket() {
   // ToDo: Ideally we want this to fail if the gid of the current
   // process is AID_LOGD, but will have to wait until we have
@@ -486,10 +485,8 @@
   uint32_t tv_sec;
   uint32_t tv_nsec;
 };
-#endif
 
 static int __libc_write_log(int priority, const char* tag, const char* msg) {
-#ifdef TARGET_USES_LOGD
   int main_log_fd = __libc_open_log_socket();
   if (main_log_fd == -1) {
     // Try stderr instead.
@@ -517,24 +514,6 @@
   vec[4].iov_len = strlen(tag) + 1;
   vec[5].iov_base = const_cast<char*>(msg);
   vec[5].iov_len = strlen(msg) + 1;
-#else
-  int main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
-  if (main_log_fd == -1) {
-    if (errno == ENOTDIR) {
-      // /dev/log isn't a directory? Maybe we're running on the host? Try stderr instead.
-      return __libc_write_stderr(tag, msg);
-    }
-    return -1;
-  }
-
-  iovec vec[3];
-  vec[0].iov_base = &priority;
-  vec[0].iov_len = 1;
-  vec[1].iov_base = const_cast<char*>(tag);
-  vec[1].iov_len = strlen(tag) + 1;
-  vec[2].iov_base = const_cast<char*>(msg);
-  vec[2].iov_len = strlen(msg) + 1;
-#endif
 
   int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
   close(main_log_fd);
@@ -557,7 +536,6 @@
 }
 
 static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
-#ifdef TARGET_USES_LOGD
   iovec vec[6];
   char log_id = LOG_ID_EVENTS;
   vec[0].iov_base = &log_id;
@@ -581,17 +559,6 @@
   vec[5].iov_len = len;
 
   int event_log_fd = __libc_open_log_socket();
-#else
-  iovec vec[3];
-  vec[0].iov_base = &tag;
-  vec[0].iov_len = sizeof(tag);
-  vec[1].iov_base = &type;
-  vec[1].iov_len = sizeof(type);
-  vec[2].iov_base = const_cast<void*>(payload);
-  vec[2].iov_len = len;
-
-  int event_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/events", O_CLOEXEC | O_WRONLY));
-#endif
 
   if (event_log_fd == -1) {
     return -1;
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index fa40b35..b01cef2 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -612,7 +612,7 @@
         error_log("Unable to open /dev/qemu_trace");
         return false;
     } else {
-        qtrace = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        qtrace = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
         close(fd);
 
         if (qtrace == MAP_FAILED) {
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index 61039b2..8a55f7e 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -97,8 +97,10 @@
     case _SC_ATEXIT_MAX:        return LONG_MAX;    // Unlimited.
     case _SC_IOV_MAX:           return UIO_MAXIOV;
 
-    case _SC_PAGESIZE:          // Fall through, PAGESIZE and PAGE_SIZE always hold the same value.
-    case _SC_PAGE_SIZE:         return static_cast<long>(getauxval(AT_PAGESZ));
+    // _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
+    case _SC_PAGESIZE:
+    case _SC_PAGE_SIZE:
+      return static_cast<long>(getauxval(AT_PAGESZ));
 
     case _SC_XOPEN_UNIX:        return _XOPEN_UNIX;
     case _SC_AIO_LISTIO_MAX:    return _POSIX_AIO_LISTIO_MAX;     // Minimum requirement.
diff --git a/libc/bionic/sysinfo.cpp b/libc/bionic/sysinfo.cpp
index 82cb76a..a48bfea 100644
--- a/libc/bionic/sysinfo.cpp
+++ b/libc/bionic/sysinfo.cpp
@@ -29,9 +29,9 @@
 #include <sys/sysinfo.h>
 
 #include <dirent.h>
-#include <limits.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "private/ScopedReaddir.h"
 
@@ -94,7 +94,7 @@
   while (fgets(buf, sizeof(buf), fp) != NULL) {
     long total;
     if (sscanf(buf, pattern, &total) == 1) {
-      page_count = static_cast<int>(total / (PAGE_SIZE / 1024));
+      page_count = static_cast<int>(total / (sysconf(_SC_PAGE_SIZE) / 1024));
       break;
     }
   }
diff --git a/libc/include/limits.h b/libc/include/limits.h
index 6ae629b..67c7719 100644
--- a/libc/include/limits.h
+++ b/libc/include/limits.h
@@ -81,17 +81,6 @@
 
 #define MB_LEN_MAX 4
 
-/* New code should use sysconf(_SC_PAGE_SIZE) instead. */
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-#ifndef PAGESIZE
-#define  PAGESIZE  PAGE_SIZE
-#endif
-
-/* glibc's PAGE_MASK is the bitwise negation of BSD's! TODO: remove? */
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-
 #define SEM_VALUE_MAX 0x3fffffff
 
 /* POSIX says these belong in <unistd.h> but BSD has some in <limits.h>. */
diff --git a/libc/include/sys/user.h b/libc/include/sys/user.h
index d63fe6a..ce4c07c 100644
--- a/libc/include/sys/user.h
+++ b/libc/include/sys/user.h
@@ -30,11 +30,13 @@
 #define _SYS_USER_H_
 
 #include <sys/cdefs.h>
-#include <limits.h> /* For PAGE_SIZE. */
 #include <stddef.h> /* For size_t. */
 
 __BEGIN_DECLS
 
+#define PAGE_SIZE 4096
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
 #if __i386__
 
 struct user_fpregs_struct {
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index f0de29e..904447c 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -224,6 +224,10 @@
     } while (_rc == -1 && errno == EINTR); \
     _rc; })
 
+extern char* __getcwd_chk(char*, size_t, size_t);
+__errordecl(__getcwd_dest_size_error, "getcwd called with size bigger than destination");
+extern char* __getcwd_real(char*, size_t) __RENAME(getcwd);
+
 extern ssize_t __pread_chk(int, void*, size_t, off_t, size_t);
 __errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
 __errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
@@ -251,6 +255,37 @@
 
 #if defined(__BIONIC_FORTIFY)
 
+__BIONIC_FORTIFY_INLINE
+char* getcwd(char* buf, size_t size) {
+    size_t bos = __bos(buf);
+
+#if defined(__clang__)
+    /*
+     * Work around LLVM's incorrect __builtin_object_size implementation here
+     * to avoid needing the workaround in the __getcwd_chk ABI forever.
+     *
+     * https://llvm.org/bugs/show_bug.cgi?id=23277
+     */
+    if (buf == NULL) {
+        bos = __BIONIC_FORTIFY_UNKNOWN_SIZE;
+    }
+#else
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __getcwd_real(buf, size);
+    }
+
+    if (__builtin_constant_p(size) && (size > bos)) {
+        __getcwd_dest_size_error();
+    }
+
+    if (__builtin_constant_p(size) && (size <= bos)) {
+        return __getcwd_real(buf, size);
+    }
+#endif
+
+    return __getcwd_chk(buf, size, bos);
+}
+
 #if defined(__USE_FILE_OFFSET64)
 #define __PREAD_PREFIX(x) __pread64_ ## x
 #else
diff --git a/libc/libc.map b/libc/libc.map
index 8c3ac9e..6117d53 100644
--- a/libc/libc.map
+++ b/libc/libc.map
@@ -1336,6 +1336,7 @@
   global:
     __fread_chk;
     __fwrite_chk;
+    __getcwd_chk;
     getgrgid_r;
     getgrnam_r;
 } LIBC;
diff --git a/libc/private/bionic_page.h b/libc/private/bionic_page.h
new file mode 100644
index 0000000..0beb708
--- /dev/null
+++ b/libc/private/bionic_page.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef _BIONIC_PAGE_H_
+#define _BIONIC_PAGE_H_
+
+// Get PAGE_SIZE and PAGE_MASK.
+#include <sys/user.h>
+
+// Returns the address of the page containing address 'x'.
+#define PAGE_START(x) ((x) & PAGE_MASK)
+
+// Returns the offset of address 'x' in its page.
+#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
+
+// Returns the address of the next page after address 'x', unless 'x' is
+// itself at the start of a page.
+#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1))
+
+#endif // _BIONIC_PAGE_H_
diff --git a/libc/upstream-openbsd/android/include/arc4random.h b/libc/upstream-openbsd/android/include/arc4random.h
index c07257d..96d9c9a 100644
--- a/libc/upstream-openbsd/android/include/arc4random.h
+++ b/libc/upstream-openbsd/android/include/arc4random.h
@@ -27,6 +27,8 @@
 #include <pthread.h>
 #include <signal.h>
 
+#include "private/bionic_prctl.h"
+
 // Android gets these from "thread_private.h".
 #include "thread_private.h"
 //static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
@@ -76,12 +78,18 @@
 	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
 		return (-1);
 
+	prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *rsp, sizeof(**rsp),
+	    "arc4random _rs structure");
+
 	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
 	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
 		munmap(*rsxp, sizeof(**rsxp));
 		return (-1);
 	}
 
+	prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *rsxp, sizeof(**rsxp),
+	    "arc4random _rsx structure");
+
 	_ARC4_ATFORK(_rs_forkhandler);
 	return (0);
 }
diff --git a/libc/upstream-openbsd/lib/libc/gen/fnmatch.c b/libc/upstream-openbsd/lib/libc/gen/fnmatch.c
index 2c860f7..0d0f18f 100644
--- a/libc/upstream-openbsd/lib/libc/gen/fnmatch.c
+++ b/libc/upstream-openbsd/lib/libc/gen/fnmatch.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fnmatch.c,v 1.17 2013/11/24 23:51:29 deraadt Exp $	*/
+/*	$OpenBSD: fnmatch.c,v 1.19 2015/08/01 18:11:08 millert Exp $	*/
 
 /* Copyright (c) 2011, VMware, Inc.
  * All rights reserved.
@@ -88,7 +88,6 @@
 #include <fnmatch.h>
 #include <string.h>
 #include <ctype.h>
-#include <limits.h>
 
 #include "charclass.h"
 
@@ -193,6 +192,8 @@
                 result = 0;
                 continue;
             }
+            if (!**pattern)
+                break;
 
 leadingclosebrace:
             /* Look at only well-formed range patterns; 
@@ -294,10 +295,6 @@
     const char *mismatch = NULL;
     int matchlen = 0;
 
-    if (strnlen(pattern, PATH_MAX) == PATH_MAX ||
-        strnlen(string, PATH_MAX) == PATH_MAX)
-            return (FNM_NOMATCH);
-
     if (*pattern == '*')
         goto firstsegment;
 
diff --git a/linker/Android.mk b/linker/Android.mk
index 04b4370..d378e90 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -60,7 +60,7 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libz liblog
+LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libbase libz liblog
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 46c97af..3731c99 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -135,9 +135,6 @@
       signal_name = "SIGILL";
       has_address = true;
       break;
-    case SIGPIPE:
-      signal_name = "SIGPIPE";
-      break;
     case SIGSEGV:
       signal_name = "SIGSEGV";
       has_address = true;
@@ -273,7 +270,7 @@
   signal(signal_number, SIG_DFL);
 
   // These signals are not re-thrown when we resume.  This means that
-  // crashing due to (say) SIGPIPE doesn't work the way you'd expect it
+  // crashing due to (say) SIGABRT doesn't work the way you'd expect it
   // to.  We work around this by throwing them manually.  We don't want
   // to do this for *all* signals because it'll screw up the si_addr for
   // faults like SIGSEGV. It does screw up the si_code, which is why we
@@ -281,7 +278,6 @@
   switch (signal_number) {
     case SIGABRT:
     case SIGFPE:
-    case SIGPIPE:
 #if defined(SIGSTKFLT)
     case SIGSTKFLT:
 #endif
@@ -307,7 +303,6 @@
   sigaction(SIGBUS, &action, nullptr);
   sigaction(SIGFPE, &action, nullptr);
   sigaction(SIGILL, &action, nullptr);
-  sigaction(SIGPIPE, &action, nullptr);
   sigaction(SIGSEGV, &action, nullptr);
 #if defined(SIGSTKFLT)
   sigaction(SIGSTKFLT, &action, nullptr);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 375b534..4428e51 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -57,6 +57,8 @@
 #include "linker_phdr.h"
 #include "linker_relocs.h"
 #include "linker_reloc_iterators.h"
+
+#include "base/strings.h"
 #include "ziparchive/zip_archive.h"
 
 extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
@@ -308,25 +310,9 @@
 
 static void parse_path(const char* path, const char* delimiters,
                        std::vector<std::string>* paths) {
-  if (path == nullptr) {
-    return;
-  }
-
   paths->clear();
-
-  for (const char *p = path; ; ++p) {
-    size_t len = strcspn(p, delimiters);
-    // skip empty tokens
-    if (len == 0) {
-      continue;
-    }
-
-    paths->push_back(std::string(p, len));
-    p += len;
-
-    if (*p == '\0') {
-      break;
-    }
+  if (path != nullptr) {
+    *paths = android::base::Split(path, delimiters);
   }
 }
 
diff --git a/linker/linker.h b/linker/linker.h
index b1d2566..6f8bf1f 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -29,13 +29,14 @@
 #ifndef _LINKER_H_
 #define _LINKER_H_
 
+#include <android/dlext.h>
 #include <elf.h>
 #include <inttypes.h>
 #include <link.h>
-#include <unistd.h>
-#include <android/dlext.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
+#include "private/bionic_page.h"
 #include "private/libc_logging.h"
 #include "linked_list.h"
 
@@ -77,16 +78,6 @@
 #define ELF64_R_TYPE(info)  (((info) >> 56) & 0xff)
 #endif
 
-// Returns the address of the page containing address 'x'.
-#define PAGE_START(x)  ((x) & PAGE_MASK)
-
-// Returns the offset of address 'x' in its page.
-#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
-
-// Returns the address of the next page after address 'x', unless 'x' is
-// itself at the start of a page.
-#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
-
 #define FLAG_LINKED     0x00000001
 #define FLAG_EXE        0x00000004 // The main executable
 #define FLAG_LINKER     0x00000010 // The linker itself
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index 75ea290..4dc97c8 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -264,10 +264,18 @@
 
   // FP ABI-variant compatibility checks for MIPS o32 ABI
   if (abiflags == nullptr) {
-    // Old compiles lack the new abiflags section.
-    // These compilers used -mfp32 -mdouble-float -modd-spreg defaults,
-    //   ie FP32 aka DOUBLE, using odd-numbered single-prec regs
-    mips_fpabi = MIPS_ABI_FP_DOUBLE;
+    // Old compilers and some translators don't emit the new abiflags section.
+    const char* filename = get_realpath();
+    size_t len = strlen(filename);
+    if (len > 4 && (strcmp(filename+len-4, ".dex") == 0 ||
+                    strcmp(filename+len-4, ".oat") == 0   )) {
+      // Assume dex2oat is compatible with target
+      mips_fpabi = MIPS_ABI_FP_XX;
+    } else {
+      // Old Android compilers used -mfp32 -mdouble-float -modd-spreg defaults,
+      //   ie FP32 aka DOUBLE, using FR=0 mode fpregs & odd single-prec fpregs
+      mips_fpabi = MIPS_ABI_FP_DOUBLE;
+    }
   } else {
     mips_fpabi = abiflags->fp_abi;
     if ( (abiflags->flags1 & MIPS_AFL_FLAGS1_ODDSPREG)
diff --git a/tests/fortify_compilation_test.cpp b/tests/fortify_compilation_test.cpp
index 166e8d9..072006e 100644
--- a/tests/fortify_compilation_test.cpp
+++ b/tests/fortify_compilation_test.cpp
@@ -262,3 +262,11 @@
   // clang should emit a warning, but doesn't
   fwrite(buf, 1, 5, stdout);
 }
+
+void test_getcwd() {
+  char buf[4];
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__getcwd_dest_size_error' declared with attribute error: getcwd called with size bigger than destination
+  // clang should emit a warning, but doesn't
+  getcwd(buf, 5);
+}
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 664e057..8f66cc8 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -623,6 +623,12 @@
   ASSERT_FORTIFY(FD_ISSET(0, set));
 }
 
+TEST_F(DEATHTEST, getcwd_fortified) {
+  char buf[1];
+  size_t ct = atoi("2"); // prevent optimizations
+  ASSERT_FORTIFY(getcwd(buf, ct));
+}
+
 TEST_F(DEATHTEST, pread_fortified) {
   char buf[1];
   size_t ct = atoi("2"); // prevent optimizations