Tell people when they've messed up with fcntl(FD_SETFD).

This is a subtle bug that even experts struggle with.

Test: treehugger
Change-Id: If9cf16a1c32c836f5688bb3374cfd21d55125b17
diff --git a/libc/bionic/fcntl.cpp b/libc/bionic/fcntl.cpp
index c508131..35af78b 100644
--- a/libc/bionic/fcntl.cpp
+++ b/libc/bionic/fcntl.cpp
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 
 #include "private/bionic_fdtrack.h"
+#include "private/bionic_fortify.h"
 
 #if defined(__LP64__)
 
@@ -44,6 +45,10 @@
   void* arg = va_arg(args, void*);
   va_end(args);
 
+  if (cmd == F_SETFD && (reinterpret_cast<uintptr_t>(arg) & ~FD_CLOEXEC) != 0) {
+    __fortify_fatal("fcntl(F_SETFD) passed non-FD_CLOEXEC flag: %p", arg);
+  }
+
   int rc = __fcntl(fd, cmd, arg);
   if (cmd == F_DUPFD) {
     return FDTRACK_CREATE_NAME("F_DUPFD", rc);
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index d50a438..862f498 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -23,6 +23,7 @@
 #include <sys/vfs.h>
 
 #include <android-base/file.h>
+#include <android-base/silent_death_test.h>
 #include <android-base/stringprintf.h>
 
 // Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
@@ -33,6 +34,8 @@
 #include <linux/magic.h>
 #endif
 
+using fcntl_DeathTest = SilentDeathTest;
+
 TEST(fcntl, fcntl_smoke) {
   int fd = open("/proc/version", O_RDONLY);
   ASSERT_TRUE(fd != -1);
@@ -356,3 +359,7 @@
   ASSERT_EQ(0, close(fd));
 #endif
 }
+
+TEST(fcntl_DeathTest, fcntl_F_SETFD) {
+  EXPECT_DEATH(fcntl(0, F_SETFD, O_NONBLOCK), "non-FD_CLOEXEC");
+}