Fix CreateAnonymousSharedMemory() not to leak FILE when returning fd.

CreateAnonymousSharedMemory() was modified to return the writable memory
handle as a file-descriptor rather than as a FILE. Since POSIX does not
provide a standard way to teardown a FILE without also close()ing the
underlying file-descriptor, this was achieved by leaking the FILE.

We now provide CreateAndOpenFdForTemporaryFileInDir(), to avoid the need
to wrap the temporary-file descriptor into a FILE at all.

Bug: 814444, 736452
Change-Id: Idd911f50f0e506de3eac91c809efb6c6d59fec10
Reviewed-on: https://chromium-review.googlesource.com/930336
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Commit-Queue: Wez <wez@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#538599}(cherry picked from commit 45a7b305282b175e11c871c1a8ac3b8336c66259)
Reviewed-on: https://chromium-review.googlesource.com/940163
Reviewed-by: Wez <wez@chromium.org>
Cr-Commit-Position: refs/branch-heads/3325@{#615}
Cr-Branched-From: bc084a8b5afa3744a74927344e304c02ae54189f-refs/heads/master@{#530369}
diff --git a/base/files/file_util.h b/base/files/file_util.h
index 780bb22..cd8a1ba5 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -185,6 +185,12 @@
 // Returns true iff |bytes| bytes have been successfully read from |fd|.
 BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes);
 
+// Performs the same function as CreateAndOpenTemporaryFileInDir(), but returns
+// the file-descriptor directly, rather than wrapping it into a FILE. Returns
+// -1 on failure.
+BASE_EXPORT int CreateAndOpenFdForTemporaryFileInDir(const FilePath& dir,
+                                                     FilePath* path);
+
 // The following functions use POSIX functionality that isn't supported by
 // Fuchsia.
 #if !defined(OS_FUCHSIA)
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index 27cd58a9..d2eb453 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -142,19 +142,6 @@
 #endif
 }
 
-// Creates and opens a temporary file in |directory|, returning the
-// file descriptor. |path| is set to the temporary file path.
-// This function does NOT unlink() the file.
-int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
-  AssertBlockingAllowed();  // For call to mkstemp().
-  *path = directory.Append(base::TempFileName());
-  const std::string& tmpdir_string = path->value();
-  // this should be OK since mkstemp just replaces characters in place
-  char* buffer = const_cast<char*>(tmpdir_string.c_str());
-
-  return HANDLE_EINTR(mkstemp(buffer));
-}
-
 #if defined(OS_LINUX) || defined(OS_AIX)
 // Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC.
 // This depends on the mount options used for /dev/shm, which vary among
@@ -165,7 +152,8 @@
   bool result = false;
   FilePath path;
 
-  ScopedFD fd(CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path));
+  ScopedFD fd(
+      CreateAndOpenFdForTemporaryFileInDir(FilePath("/dev/shm"), &path));
   if (fd.is_valid()) {
     DeleteFile(path, false);
     long sysconf_result = sysconf(_SC_PAGESIZE);
@@ -540,6 +528,17 @@
 
 #if !defined(OS_NACL_NONSFI)
 
+int CreateAndOpenFdForTemporaryFileInDir(const FilePath& directory,
+                                         FilePath* path) {
+  AssertBlockingAllowed();  // For call to mkstemp().
+  *path = directory.Append(TempFileName());
+  const std::string& tmpdir_string = path->value();
+  // this should be OK since mkstemp just replaces characters in place
+  char* buffer = const_cast<char*>(tmpdir_string.c_str());
+
+  return HANDLE_EINTR(mkstemp(buffer));
+}
+
 #if !defined(OS_FUCHSIA)
 bool CreateSymbolicLink(const FilePath& target_path,
                         const FilePath& symlink_path) {
@@ -668,7 +667,7 @@
   FilePath directory;
   if (!GetTempDir(&directory))
     return false;
-  int fd = CreateAndOpenFdForTemporaryFile(directory, path);
+  int fd = CreateAndOpenFdForTemporaryFileInDir(directory, path);
   if (fd < 0)
     return false;
   close(fd);
@@ -676,7 +675,7 @@
 }
 
 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
-  int fd = CreateAndOpenFdForTemporaryFile(dir, path);
+  int fd = CreateAndOpenFdForTemporaryFileInDir(dir, path);
   if (fd < 0)
     return nullptr;
 
@@ -688,7 +687,7 @@
 
 bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
   AssertBlockingAllowed();  // For call to close().
-  int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
+  int fd = CreateAndOpenFdForTemporaryFileInDir(dir, temp_file);
   return ((fd >= 0) && !IGNORE_EINTR(close(fd)));
 }
 
diff --git a/base/memory/shared_memory_helper.cc b/base/memory/shared_memory_helper.cc
index 91893d3..f98b734 100644
--- a/base/memory/shared_memory_helper.cc
+++ b/base/memory/shared_memory_helper.cc
@@ -41,13 +41,12 @@
   // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
   FilePath directory;
   ScopedPathUnlinker path_unlinker;
-  ScopedFILE fp;
   if (!GetShmemTempDir(options.executable, &directory))
     return false;
 
-  fp.reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
+  fd->reset(base::CreateAndOpenFdForTemporaryFileInDir(directory, path));
 
-  if (!fp)
+  if (!fd->is_valid())
     return false;
 
   // Deleting the file prevents anyone else from mapping it in (making it
@@ -60,10 +59,10 @@
     readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
     if (!readonly_fd->is_valid()) {
       DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
+      fd->reset();
       return false;
     }
   }
-  fd->reset(fileno(fp.release()));
   return true;
 }