Bug 1190252 - Remove use of std::ifstream in GMPChild.cpp. r=edwin
☠☠ backed out by fa8755511ac2 ☠ ☠
authorChris Pearce <cpearce@mozilla.com>
Tue, 04 Aug 2015 09:07:19 +1200
changeset 287643 880fc4c49f7e870956ae23f1b5d159ab9d3afcb5
parent 287642 ba77cb6046b78898945248da5fd459a98f97f19c
child 287644 d69d9a16becb8e4aca2dc0d20c66bc180137a45a
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1190252
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1190252 - Remove use of std::ifstream in GMPChild.cpp. r=edwin
dom/media/gmp/GMPChild.cpp
dom/media/gmp/GMPChild.h
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -14,20 +14,25 @@
 #include "GMPVideoHost.h"
 #include "nsDebugImpl.h"
 #include "nsIFile.h"
 #include "nsXULAppAPI.h"
 #include "gmp-video-decode.h"
 #include "gmp-video-encode.h"
 #include "GMPPlatform.h"
 #include "mozilla/dom/CrashReporterChild.h"
+#include "nsPrintfCString.h"
+#include "mozilla/Tokenizer.h"
+#include "nsIInputStream.h"
+#include "nsILineInputStream.h"
+#include "nsNetUtil.h"
 #ifdef XP_WIN
 #include "nsCRT.h"
 #endif
-#include <fstream>
+#include "prio.h"
 
 using mozilla::dom::CrashReporterChild;
 
 static const int MAX_VOUCHER_LENGTH = 500000;
 
 #ifdef XP_WIN
 #include <stdlib.h> // for _exit()
 #else
@@ -294,80 +299,130 @@ GMPErr
 GMPChild::GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI)
 {
   if (!mGMPLoader) {
     return GMPGenericErr;
   }
   return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI);
 }
 
+static bool
+ReadIntoArray(nsIFile* aFile,
+              nsTArray<uint8_t>& aOutDst,
+              size_t aMaxLength)
+{
+  if (!FileExists(aFile)) {
+    return false;
+  }
+
+  PRFileDesc* fd = nullptr;
+  nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+
+  int32_t length = PR_Seek(fd, 0, PR_SEEK_END);
+  PR_Seek(fd, 0, PR_SEEK_SET);
+
+  if (length < 0 || (size_t)length > aMaxLength) {
+    NS_WARNING("EME file is longer than maximum allowed length");
+    PR_Close(fd);
+    return false;
+  }
+  aOutDst.SetLength(length);
+  int32_t bytesRead = PR_Read(fd, aOutDst.Elements(), length);
+  PR_Close(fd);
+  return (bytesRead == length);
+}
+
 #ifdef XP_WIN
+static bool
+ReadIntoString(nsIFile* aFile,
+               nsCString& aOutDst,
+               size_t aMaxLength)
+{
+  nsTArray<uint8_t> buf;
+  bool rv = ReadIntoArray(aFile, buf, aMaxLength);
+  if (rv) {
+    aOutDst = nsDependentCString((const char*)buf.Elements(), buf.Length());
+  }
+  return rv;
+}
+
+static nsTArray<nsCString>
+SplitAt(Tokenizer::Token aDelim, const nsACString& aInput)
+{
+  nsTArray<nsCString> tokens;
+  Tokenizer tokenizer(aInput);
+
+  while (!tokenizer.HasFailed()) {
+    tokenizer.Record();
+    Tokenizer::Token token;
+    while (tokenizer.Next(token) && !token.Equals(aDelim))
+      ; // Skip up to next delimeter, or EOF.
+    nsAutoCString value;
+    tokenizer.Claim(value);
+    tokens.AppendElement(value);
+  }
+  return tokens;
+}
+
 // Pre-load DLLs that need to be used by the EME plugin but that can't be
 // loaded after the sandbox has started
 bool
 GMPChild::PreLoadLibraries(const nsAString& aPluginPath)
 {
   // This must be in sorted order and lowercase!
-  static const char* whitelist[] =
-    {
-       "d3d9.dll", // Create an `IDirect3D9` to get adapter information
-       "dxva2.dll", // Get monitor information
-       "evr.dll", // MFGetStrideForBitmapInfoHeader
-       "mfh264dec.dll", // H.264 decoder (on Windows Vista)
-       "mfheaacdec.dll", // AAC decoder (on Windows Vista)
-       "mfplat.dll", // MFCreateSample, MFCreateAlignedMemoryBuffer, MFCreateMediaType
-       "msauddecmft.dll", // AAC decoder (on Windows 8)
-       "msmpeg2adec.dll", // AAC decoder (on Windows 7)
-       "msmpeg2vdec.dll", // H.264 decoder
-    };
-  static const int whitelistLen = sizeof(whitelist) / sizeof(whitelist[0]);
+  static const char* whitelist[] = {
+    "d3d9.dll", // Create an `IDirect3D9` to get adapter information
+    "dxva2.dll", // Get monitor information
+    "evr.dll", // MFGetStrideForBitmapInfoHeader
+    "mfh264dec.dll", // H.264 decoder (on Windows Vista)
+    "mfheaacdec.dll", // AAC decoder (on Windows Vista)
+    "mfplat.dll", // MFCreateSample, MFCreateAlignedMemoryBuffer, MFCreateMediaType
+    "msauddecmft.dll", // AAC decoder (on Windows 8)
+    "msmpeg2adec.dll", // AAC decoder (on Windows 7)
+    "msmpeg2vdec.dll", // H.264 decoder
+  };
 
   nsCOMPtr<nsIFile> infoFile;
   GetInfoFile(aPluginPath, infoFile);
 
-  nsString path;
-  infoFile->GetPath(path);
-
-  std::ifstream stream;
-#ifdef _MSC_VER
-  // Must use UTF16 for Windows for paths for non-Latin characters.
-  stream.open(static_cast<const wchar_t*>(path.get()));
-#else
-  stream.open(NS_ConvertUTF16toUTF8(path).get());
-#endif
-  if (!stream.good()) {
-    NS_WARNING("Failure opening info file for required DLLs");
+  static const size_t MAX_GMP_INFO_FILE_LENGTH = 5 * 1024;
+  nsAutoCString info;
+  if (!ReadIntoString(infoFile, info, MAX_GMP_INFO_FILE_LENGTH)) {
+    NS_WARNING("Failed to read info file in GMP process.");
     return false;
   }
 
-  do {
-    std::string line;
-    getline(stream, line);
-    if (stream.fail()) {
-      NS_WARNING("Failure reading info file for required DLLs");
-      return false;
+  nsTArray<nsCString> lines = SplitAt(Tokenizer::Token::NewLine(), info);
+  for (nsCString line : lines) {
+    // Make lowercase.
+    std::transform(line.BeginWriting(),
+                   line.EndWriting(),
+                   line.BeginWriting(),
+                   tolower);
+
+    int32_t offset = line.Find("libraries:", false, 0);
+    if (offset == kNotFound) {
+      continue;
     }
-    std::transform(line.begin(), line.end(), line.begin(), tolower);
-    static const char* prefix = "libraries:";
-    static const int prefixLen = strlen(prefix);
-    if (0 == line.compare(0, prefixLen, prefix)) {
-      char* lineCopy = strdup(line.c_str() + prefixLen);
-      char* start = lineCopy;
-      while (char* tok = nsCRT::strtok(start, ", ", &start)) {
-        for (int i = 0; i < whitelistLen; i++) {
-          if (0 == strcmp(whitelist[i], tok)) {
-            LoadLibraryA(tok);
-            break;
-          }
+    // Line starts with "libraries:".
+    nsTArray<nsCString> libs = SplitAt(Tokenizer::Token::Char(','),
+                                       Substring(line, offset));
+    for (nsCString lib : libs) {
+      lib.Trim(" ");
+      for (const char* whiteListedLib : whitelist) {
+        if (lib.EqualsASCII(whiteListedLib)) {
+          LoadLibraryA(lib.get());
+          break;
         }
       }
-      free(lineCopy);
-      break;
     }
-  } while (!stream.eof());
+  }
 
   return true;
 }
 #endif
 
 bool
 GMPChild::GetUTF8LibPath(nsACString& aOutLibPath)
 {
@@ -400,17 +455,17 @@ GMPChild::GetUTF8LibPath(nsACString& aOu
 bool
 GMPChild::RecvStartPlugin()
 {
   LOGD("%s", __FUNCTION__);
 
 #if defined(XP_WIN)
   PreLoadLibraries(mPluginPath);
 #endif
-  if (!PreLoadPluginVoucher(mPluginPath)) {
+  if (!PreLoadPluginVoucher()) {
     NS_WARNING("Plugin voucher failed to load!");
     return false;
   }
   PreLoadSandboxVoucher();
 
   nsCString libPath;
   if (!GetUTF8LibPath(libPath)) {
     return false;
@@ -605,106 +660,59 @@ void
 GMPChild::ShutdownComplete()
 {
   LOGD("%s", __FUNCTION__);
   MOZ_ASSERT(mGMPMessageLoop == MessageLoop::current());
   mAsyncShutdown = nullptr;
   SendAsyncShutdownComplete();
 }
 
-static bool
+static void
 GetPluginVoucherFile(const nsAString& aPluginPath,
                      nsCOMPtr<nsIFile>& aOutVoucherFile)
 {
   nsAutoString baseName;
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   nsCOMPtr<nsIFile> libDir;
   GetFileBase(aPluginPath, aOutVoucherFile, libDir, baseName);
 #else
   GetFileBase(aPluginPath, aOutVoucherFile, baseName);
 #endif
   nsAutoString infoFileName = baseName + NS_LITERAL_STRING(".voucher");
   aOutVoucherFile->AppendRelativePath(infoFileName);
-  return true;
 }
 
 bool
-GMPChild::PreLoadPluginVoucher(const nsAString& aPluginPath)
+GMPChild::PreLoadPluginVoucher()
 {
   nsCOMPtr<nsIFile> voucherFile;
-  GetPluginVoucherFile(aPluginPath, voucherFile);
-
+  GetPluginVoucherFile(mPluginPath, voucherFile);
   if (!FileExists(voucherFile)) {
+    // Assume missing file is not fatal; that would break OpenH264.
     return true;
   }
-
-  nsString path;
-  voucherFile->GetPath(path);
-
-  std::ifstream stream;
-  #ifdef _MSC_VER
-  // Must use UTF16 for Windows for paths for non-Latin characters.
-  stream.open(static_cast<const wchar_t*>(path.get()), std::ios::binary);
-  #else
-  stream.open(NS_ConvertUTF16toUTF8(path).get(), std::ios::binary);
-  #endif
-  if (!stream.good()) {
-    return false;
-  }
-
-  std::streampos start = stream.tellg();
-  stream.seekg (0, std::ios::end);
-  std::streampos end = stream.tellg();
-  stream.seekg (0, std::ios::beg);
-  auto length = end - start;
-  if (length > MAX_VOUCHER_LENGTH) {
-    NS_WARNING("Plugin voucher file too big!");
-    return false;
-  }
-
-  mPluginVoucher.SetLength(length);
-  stream.read((char*)mPluginVoucher.Elements(), length);
-  if (!stream) {
-    NS_WARNING("Failed to read plugin voucher file!");
-    return false;
-  }
-
-  return true;
+  return ReadIntoArray(voucherFile, mPluginVoucher, MAX_VOUCHER_LENGTH);
 }
 
 void
 GMPChild::PreLoadSandboxVoucher()
 {
-  std::ifstream stream;
-  #ifdef _MSC_VER
-  // Must use UTF16 for Windows for paths for non-Latin characters.
-  stream.open(static_cast<const wchar_t*>(mSandboxVoucherPath.get()), std::ios::binary);
-  #else
-  stream.open(NS_ConvertUTF16toUTF8(mSandboxVoucherPath).get(), std::ios::binary);
-  #endif
-  if (!stream.good()) {
-    NS_WARNING("PreLoadSandboxVoucher can't find sandbox voucher file!");
+  nsCOMPtr<nsIFile> f;
+  nsresult rv = NS_NewLocalFile(mSandboxVoucherPath, true, getter_AddRefs(f));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create nsIFile for sandbox voucher");
+    return;
+  }
+  if (!FileExists(f)) {
+    // Assume missing file is not fatal; that would break OpenH264.
     return;
   }
 
-  std::streampos start = stream.tellg();
-  stream.seekg (0, std::ios::end);
-  std::streampos end = stream.tellg();
-  stream.seekg (0, std::ios::beg);
-  auto length = end - start;
-  if (length > MAX_VOUCHER_LENGTH) {
-    NS_WARNING("PreLoadSandboxVoucher sandbox voucher file too big!");
-    return;
-  }
-
-  mSandboxVoucher.SetLength(length);
-  stream.read((char*)mSandboxVoucher.Elements(), length);
-  if (!stream) {
-    NS_WARNING("PreLoadSandboxVoucher failed to read plugin voucher file!");
-    return;
+  if (!ReadIntoArray(f, mSandboxVoucher, MAX_VOUCHER_LENGTH)) {
+    NS_WARNING("Failed to read sandbox voucher");
   }
 }
 
 PGMPContentChild*
 GMPChild::AllocPGMPContentChild(Transport* aTransport,
                                 ProcessId aOtherPid)
 {
   GMPContentChild* child =
--- a/dom/media/gmp/GMPChild.h
+++ b/dom/media/gmp/GMPChild.h
@@ -45,17 +45,17 @@ public:
 
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   bool SetMacSandboxInfo();
 #endif
 
 private:
   friend class GMPContentChild;
 
-  bool PreLoadPluginVoucher(const nsAString& aPluginPath);
+  bool PreLoadPluginVoucher();
   void PreLoadSandboxVoucher();
 
   bool GetUTF8LibPath(nsACString& aOutLibPath);
 
   virtual bool RecvSetNodeId(const nsCString& aNodeId) override;
   virtual bool RecvStartPlugin() override;
 
   virtual PCrashReporterChild* AllocPCrashReporterChild(const NativeThreadId& aThread) override;