Bug 1427012 - make the stream class used in printing more resilient to runtime errors, instead of crashing; r?bobowen draft
authorAlex Gaynor <agaynor@mozilla.com>
Fri, 05 Jan 2018 14:52:54 -0500
changeset 717867 2d42d99c236592e27796b863ae64c7088109b4ea
parent 717738 6f5fac320fcb6625603fa8a744ffa8523f8b3d71
child 745369 4090cbbd516965263c1890d8c8c77a0ee1ff37eb
push id94802
push userbmo:agaynor@mozilla.com
push dateTue, 09 Jan 2018 18:41:18 +0000
reviewersbobowen
bugs1427012
milestone59.0a1
Bug 1427012 - make the stream class used in printing more resilient to runtime errors, instead of crashing; r?bobowen MozReview-Commit-ID: 6ExIvOAWfQX
layout/printing/DrawEventRecorder.h
--- a/layout/printing/DrawEventRecorder.h
+++ b/layout/printing/DrawEventRecorder.h
@@ -19,22 +19,24 @@ namespace layout {
 class PRFileDescStream : public mozilla::gfx::EventStream {
   // Most writes, as seen in the print IPC use case, are very small (<32 bytes),
   // with a small number of very large (>40KB) writes. Writes larger than this
   // value are not buffered.
   static const size_t kBufferSize = 1024;
 public:
   PRFileDescStream() : mFd(nullptr), mBuffer(nullptr), mBufferPos(0),
                        mGood(true) {}
+  PRFileDescStream(const PRFileDescStream& other) = delete;
+  ~PRFileDescStream() { Close(); }
 
   void OpenFD(PRFileDesc* aFd)
   {
     MOZ_ASSERT(!IsOpen());
     mFd = aFd;
-    mGood = true;
+    mGood = !!mFd;
     mBuffer.reset(new uint8_t[kBufferSize]);
     mBufferPos = 0;
   }
 
   void Close() {
     // We need to be API compatible with std::ostream, and so we silently handle
     // closes on a closed FD.
     if (IsOpen()) {
@@ -48,55 +50,67 @@ public:
 
   bool IsOpen() {
     return mFd != nullptr;
   }
 
   void Flush() {
     // See comment in Close().
     if (IsOpen() && mBufferPos > 0) {
-      PR_Write(mFd, static_cast<const void*>(mBuffer.get()), mBufferPos);
+      PRInt32 length =
+        PR_Write(mFd, static_cast<const void*>(mBuffer.get()), mBufferPos);
+      mGood = length >= 0 && static_cast<size_t>(length) == mBufferPos;
       mBufferPos = 0;
     }
   }
 
-  void Seek(PRInt32 aOffset, PRSeekWhence aWhence) {
+  void Seek(PRInt64 aOffset, PRSeekWhence aWhence)
+  {
     Flush();
-    PR_Seek(mFd, aOffset, aWhence);
+    PRInt64 pos = PR_Seek64(mFd, aOffset, aWhence);
+    mGood = pos != -1;
   }
 
   void write(const char* aData, size_t aSize) {
+    if (!good()) {
+      return;
+    }
+
     // See comment in Close().
     if (IsOpen()) {
       // If we're writing more data than could ever fit in our buffer, flush the
       // buffer and write directly.
       if (aSize > kBufferSize) {
         Flush();
-        PR_Write(mFd, static_cast<const void*>(aData), aSize);
-      // If our write could fit in our buffer, but doesn't because the buffer is
-      // partially full, write to the buffer, flush the buffer, and then write
-      // the rest of the data to the buffer.
+        PRInt32 length = PR_Write(mFd, static_cast<const void*>(aData), aSize);
+        mGood = length >= 0 && static_cast<size_t>(length) == aSize;
+      // If our write could fit in our buffer, but doesn't because the buffer
+      // is partially full, write to the buffer, flush the buffer, and then
+      // write the rest of the data to the buffer.
       } else if (aSize > AvailableBufferSpace()) {
         size_t length = AvailableBufferSpace();
         WriteToBuffer(aData, length);
         Flush();
 
-        MOZ_ASSERT(aSize <= kBufferSize);
         WriteToBuffer(aData + length, aSize - length);
       // Write fits in the buffer.
       } else {
         WriteToBuffer(aData, aSize);
       }
     }
   }
 
   void read(char* aOut, size_t aSize) {
+    if (!good()) {
+      return;
+    }
+
     Flush();
     PRInt32 res = PR_Read(mFd, static_cast<void*>(aOut), aSize);
-    mGood = res >= 0 && ((size_t)res == aSize);
+    mGood = res >= 0 && (static_cast<size_t>(res) == aSize);
   }
 
   bool good() {
     return mGood;
   }
 
 private:
   size_t AvailableBufferSpace() {