Make {A85,RunLength}Encode()'s buffer out parameter a unique_ptr.

Change-Id: I3f06ea7ed39c8a8fff57e07f14ff6c21bedbc028
Reviewed-on: https://pdfium-review.googlesource.com/c/43998
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcodec/codec/ccodec_basicmodule.h b/core/fxcodec/codec/ccodec_basicmodule.h
index 2ad3740..72dd016 100644
--- a/core/fxcodec/codec/ccodec_basicmodule.h
+++ b/core/fxcodec/codec/ccodec_basicmodule.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "core/fxcrt/fx_memory.h"
 #include "core/fxcrt/fx_system.h"
 #include "third_party/base/span.h"
 
@@ -24,11 +25,11 @@
       int bpc);
 
   bool RunLengthEncode(pdfium::span<const uint8_t> src_buf,
-                       uint8_t** dest_buf,
+                       std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
                        uint32_t* dest_size);
 
   bool A85Encode(pdfium::span<const uint8_t> src_buf,
-                 uint8_t** dest_buf,
+                 std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
                  uint32_t* dest_size);
 };
 
diff --git a/core/fxcodec/codec/fx_codec.cpp b/core/fxcodec/codec/fx_codec.cpp
index d38f10a..f2c8e18 100644
--- a/core/fxcodec/codec/fx_codec.cpp
+++ b/core/fxcodec/codec/fx_codec.cpp
@@ -1357,20 +1357,22 @@
 
 CCodec_ModuleMgr::~CCodec_ModuleMgr() {}
 
-bool CCodec_BasicModule::RunLengthEncode(pdfium::span<const uint8_t> src_span,
-                                         uint8_t** dest_buf,
-                                         uint32_t* dest_size) {
+bool CCodec_BasicModule::RunLengthEncode(
+    pdfium::span<const uint8_t> src_span,
+    std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+    uint32_t* dest_size) {
   // Check inputs
   if (src_span.empty() || !dest_buf || !dest_size)
     return false;
 
   // Edge case
   if (src_span.size() == 1) {
-    *dest_buf = FX_Alloc(uint8_t, 3);
-    (*dest_buf)[0] = 0;
-    (*dest_buf)[1] = src_span[0];
-    (*dest_buf)[2] = 128;
     *dest_size = 3;
+    dest_buf->reset(FX_Alloc(uint8_t, *dest_size));
+    auto dest_buf_span = pdfium::make_span(dest_buf->get(), *dest_size);
+    dest_buf_span[0] = 0;
+    dest_buf_span[1] = src_span[0];
+    dest_buf_span[2] = 128;
     return true;
   }
 
@@ -1382,10 +1384,10 @@
   estimated_size /= 3;
   estimated_size *= 4;
   estimated_size += 1;
-  *dest_buf = FX_Alloc(uint8_t, estimated_size.ValueOrDie());
+  dest_buf->reset(FX_Alloc(uint8_t, estimated_size.ValueOrDie()));
 
   // Set up pointers.
-  uint8_t* out = *dest_buf;
+  uint8_t* out = dest_buf->get();
   uint32_t run_start = 0;
   uint32_t run_end = 1;
   uint8_t x = src_span[run_start];
@@ -1436,13 +1438,14 @@
     out += 2;
   }
   *out = 128;
-  *dest_size = out + 1 - *dest_buf;
+  *dest_size = out + 1 - dest_buf->get();
   return true;
 }
 
-bool CCodec_BasicModule::A85Encode(pdfium::span<const uint8_t> src_span,
-                                   uint8_t** dest_buf,
-                                   uint32_t* dest_size) {
+bool CCodec_BasicModule::A85Encode(
+    pdfium::span<const uint8_t> src_span,
+    std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+    uint32_t* dest_size) {
   // Check inputs.
   if (!dest_buf || !dest_size)
     return false;
@@ -1461,10 +1464,10 @@
   estimated_size += 4;
   estimated_size += src_span.size() / 30;
   estimated_size += 2;
-  *dest_buf = FX_Alloc(uint8_t, estimated_size.ValueOrDie());
+  dest_buf->reset(FX_Alloc(uint8_t, estimated_size.ValueOrDie()));
 
   // Set up pointers.
-  uint8_t* out = *dest_buf;
+  uint8_t* out = dest_buf->get();
   uint32_t pos = 0;
   uint32_t line_length = 0;
   while (src_span.size() >= 4 && pos < src_span.size() - 3) {
@@ -1511,7 +1514,7 @@
   out[0] = '~';
   out[1] = '>';
   out += 2;
-  *dest_size = out - *dest_buf;
+  *dest_size = out - dest_buf->get();
   return true;
 }
 
diff --git a/core/fxcodec/codec/fx_codec_a85_unittest.cpp b/core/fxcodec/codec/fx_codec_a85_unittest.cpp
index e0b6964..1372858 100644
--- a/core/fxcodec/codec/fx_codec_a85_unittest.cpp
+++ b/core/fxcodec/codec/fx_codec_a85_unittest.cpp
@@ -5,6 +5,7 @@
 #include <stdint.h>
 
 #include <limits>
+#include <memory>
 
 #include "core/fxcodec/codec/ccodec_basicmodule.h"
 #include "core/fxcodec/fx_codec.h"
@@ -12,7 +13,7 @@
 
 TEST(fxcodec, A85TestBadInputs) {
   const uint8_t src_buf[] = {1, 2, 3, 4};
-  uint8_t* dest_buf = nullptr;
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
   uint32_t dest_size = 0;
 
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
@@ -26,135 +27,141 @@
 
 // No leftover bytes, just translate 2 sets of symbols.
 TEST(fxcodec, A85TestBasic) {
-  // Make sure really big values don't break.
-  const uint8_t src_buf[] = {1, 2, 3, 4, 255, 255, 255, 255};
-  uint8_t* dest_buf = nullptr;
-  uint32_t dest_size = 0;
-
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
   EXPECT_TRUE(pEncoders);
 
-  // Should succeed.
+  // Make sure really big values don't break.
+  const uint8_t src_buf[] = {1, 2, 3, 4, 255, 255, 255, 255};
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
+  uint32_t dest_size = 0;
   EXPECT_TRUE(pEncoders->A85Encode(src_buf, &dest_buf, &dest_size));
 
   // Should have 5 chars for each set of 4 and 2 terminators.
-  ASSERT_EQ(12u, dest_size);
   const uint8_t expected_out[] = {33, 60, 78, 63, 43,  115,
                                   56, 87, 45, 33, 126, 62};
+  ASSERT_EQ(FX_ArraySize(expected_out), dest_size);
 
   // Check the output
-  for (uint32_t i = 0; i < 12; i++)
-    EXPECT_EQ(expected_out[i], dest_buf[i]) << " at " << i;
-  FX_Free(dest_buf);
+  auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+  for (uint32_t i = 0; i < dest_size; i++)
+    EXPECT_EQ(expected_out[i], dest_buf_span[i]) << " at " << i;
 }
 
 // Leftover bytes.
 TEST(fxcodec, A85TestLeftoverBytes) {
-  // 1 Leftover Byte:
-  const uint8_t src_buf_1leftover[] = {1, 2, 3, 4, 255};
-  uint8_t* dest_buf = nullptr;
-  uint32_t dest_size = 0;
-
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
   EXPECT_TRUE(pEncoders);
 
-  // Should succeed
-  EXPECT_TRUE(pEncoders->A85Encode(src_buf_1leftover, &dest_buf, &dest_size));
-  ASSERT_EQ(9u, dest_size);  // 5 chars for first symbol + 2 + 2 terminators.
-  uint8_t expected_out_1leftover[] = {33, 60, 78, 63, 43, 114, 114, 126, 62};
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
+  uint32_t dest_size = 0;
 
-  // Check the output
-  for (uint32_t i = 0; i < 9; i++)
-    EXPECT_EQ(expected_out_1leftover[i], dest_buf[i]) << " at " << i;
-  FX_Free(dest_buf);
+  {
+    // 1 Leftover Byte:
+    const uint8_t src_buf_1leftover[] = {1, 2, 3, 4, 255};
+    EXPECT_TRUE(pEncoders->A85Encode(src_buf_1leftover, &dest_buf, &dest_size));
 
-  // 2 Leftover bytes:
-  const uint8_t src_buf_2leftover[] = {1, 2, 3, 4, 255, 254};
-  dest_buf = nullptr;
-  dest_size = 0;
-  // Should succeed
-  EXPECT_TRUE(pEncoders->A85Encode(src_buf_2leftover, &dest_buf, &dest_size));
-  ASSERT_EQ(10u, dest_size);  // 5 chars for first symbol + 3 + 2 terminators.
-  const uint8_t expected_out_2leftover[] = {33,  60, 78, 63,  43,
-                                            115, 56, 68, 126, 62};
+    // 5 chars for first symbol + 2 + 2 terminators.
+    uint8_t expected_out_1leftover[] = {33, 60, 78, 63, 43, 114, 114, 126, 62};
+    ASSERT_EQ(FX_ArraySize(expected_out_1leftover), dest_size);
 
-  // Check the output
-  for (uint32_t i = 0; i < 10; i++)
-    EXPECT_EQ(expected_out_2leftover[i], dest_buf[i]) << " at " << i;
-  FX_Free(dest_buf);
+    // Check the output
+    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+    for (uint32_t i = 0; i < dest_size; i++)
+      EXPECT_EQ(expected_out_1leftover[i], dest_buf_span[i]) << " at " << i;
+  }
 
-  // 3 Leftover bytes:
-  const uint8_t src_buf_3leftover[] = {1, 2, 3, 4, 255, 254, 253};
-  dest_buf = nullptr;
-  dest_size = 0;
-  // Should succeed
-  EXPECT_TRUE(pEncoders->A85Encode(src_buf_3leftover, &dest_buf, &dest_size));
-  ASSERT_EQ(11u, dest_size);  // 5 chars for first symbol + 4 + 2 terminators.
-  const uint8_t expected_out_3leftover[] = {33, 60, 78,  63,  43, 115,
-                                            56, 77, 114, 126, 62};
+  {
+    // 2 Leftover bytes:
+    const uint8_t src_buf_2leftover[] = {1, 2, 3, 4, 255, 254};
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->A85Encode(src_buf_2leftover, &dest_buf, &dest_size));
+    // 5 chars for first symbol + 3 + 2 terminators.
+    const uint8_t expected_out_2leftover[] = {33,  60, 78, 63,  43,
+                                              115, 56, 68, 126, 62};
+    ASSERT_EQ(FX_ArraySize(expected_out_2leftover), dest_size);
 
-  // Check the output
-  for (uint32_t i = 0; i < 11; i++)
-    EXPECT_EQ(expected_out_3leftover[i], dest_buf[i]) << " at " << i;
-  FX_Free(dest_buf);
+    // Check the output
+    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+    for (uint32_t i = 0; i < dest_size; i++)
+      EXPECT_EQ(expected_out_2leftover[i], dest_buf_span[i]) << " at " << i;
+  }
+
+  {
+    // 3 Leftover bytes:
+    const uint8_t src_buf_3leftover[] = {1, 2, 3, 4, 255, 254, 253};
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->A85Encode(src_buf_3leftover, &dest_buf, &dest_size));
+    // 5 chars for first symbol + 4 + 2 terminators.
+    const uint8_t expected_out_3leftover[] = {33, 60, 78,  63,  43, 115,
+                                              56, 77, 114, 126, 62};
+    ASSERT_EQ(FX_ArraySize(expected_out_3leftover), dest_size);
+
+    // Check the output
+    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+    for (uint32_t i = 0; i < dest_size; i++)
+      EXPECT_EQ(expected_out_3leftover[i], dest_buf_span[i]) << " at " << i;
+  }
 }
 
 // Test all zeros comes through as "z".
 TEST(fxcodec, A85TestZeros) {
-  // Make sure really big values don't break.
-  const uint8_t src_buf[] = {1, 2, 3, 4, 0, 0, 0, 0};
-  uint8_t* dest_buf = nullptr;
-  uint32_t dest_size = 0;
-
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
   EXPECT_TRUE(pEncoders);
 
-  // Should succeed.
-  EXPECT_TRUE(pEncoders->A85Encode(src_buf, &dest_buf, &dest_size));
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
+  uint32_t dest_size = 0;
 
-  // Should have 5 chars for first set of 4 + 1 for z + 2 terminators.
-  ASSERT_EQ(8u, dest_size);
-  const uint8_t expected_out[] = {33, 60, 78, 63, 43, 122, 126, 62};
+  {
+    // Make sure really big values don't break.
+    const uint8_t src_buf[] = {1, 2, 3, 4, 0, 0, 0, 0};
+    EXPECT_TRUE(pEncoders->A85Encode(src_buf, &dest_buf, &dest_size));
 
-  // Check the output
-  for (uint32_t i = 0; i < 8; i++)
-    EXPECT_EQ(expected_out[i], dest_buf[i]) << " at " << i;
-  FX_Free(dest_buf);
+    // Should have 5 chars for first set of 4 + 1 for z + 2 terminators.
+    const uint8_t expected_out[] = {33, 60, 78, 63, 43, 122, 126, 62};
+    ASSERT_EQ(FX_ArraySize(expected_out), dest_size);
 
-  // Should also work if it is at the start:
-  const uint8_t src_buf_2[] = {0, 0, 0, 0, 1, 2, 3, 4};
-  dest_buf = nullptr;
-  dest_size = 0;
+    // Check the output
+    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+    for (uint32_t i = 0; i < dest_size; i++)
+      EXPECT_EQ(expected_out[i], dest_buf_span[i]) << " at " << i;
+  }
 
-  // Should succeed.
-  EXPECT_TRUE(pEncoders->A85Encode(src_buf_2, &dest_buf, &dest_size));
+  {
+    // Should also work if it is at the start:
+    const uint8_t src_buf_2[] = {0, 0, 0, 0, 1, 2, 3, 4};
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->A85Encode(src_buf_2, &dest_buf, &dest_size));
 
-  // Should have 5 chars for set of 4 + 1 for z + 2 terminators.
-  ASSERT_EQ(8u, dest_size);
-  const uint8_t expected_out_2[] = {122, 33, 60, 78, 63, 43, 126, 62};
+    // Should have 5 chars for set of 4 + 1 for z + 2 terminators.
+    const uint8_t expected_out_2[] = {122, 33, 60, 78, 63, 43, 126, 62};
+    ASSERT_EQ(FX_ArraySize(expected_out_2), dest_size);
 
-  // Check the output
-  for (uint32_t i = 0; i < 8; i++)
-    EXPECT_EQ(expected_out_2[i], dest_buf[i]) << " at " << i;
-  FX_Free(dest_buf);
+    // Check the output
+    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+    for (uint32_t i = 0; i < dest_size; i++)
+      EXPECT_EQ(expected_out_2[i], dest_buf_span[i]) << " at " << i;
+  }
 
-  // Try with 2 leftover zero bytes. Make sure we don't get a "z".
-  const uint8_t src_buf_3[] = {1, 2, 3, 4, 0, 0};
-  dest_buf = nullptr;
-  dest_size = 0;
+  {
+    // Try with 2 leftover zero bytes. Make sure we don't get a "z".
+    const uint8_t src_buf_3[] = {1, 2, 3, 4, 0, 0};
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->A85Encode(src_buf_3, &dest_buf, &dest_size));
 
-  // Should succeed.
-  EXPECT_TRUE(pEncoders->A85Encode(src_buf_3, &dest_buf, &dest_size));
+    // Should have 5 chars for set of 4 + 3 for last 2 + 2 terminators.
+    const uint8_t expected_out_leftover[] = {33, 60, 78, 63,  43,
+                                             33, 33, 33, 126, 62};
+    ASSERT_EQ(FX_ArraySize(expected_out_leftover), dest_size);
 
-  // Should have 5 chars for set of 4 + 3 for last 2 + 2 terminators.
-  ASSERT_EQ(10u, dest_size);
-  const uint8_t expected_out_leftover[] = {33, 60, 78, 63,  43,
-                                           33, 33, 33, 126, 62};
-
-  // Check the output
-  for (uint32_t i = 0; i < 10; i++)
-    EXPECT_EQ(expected_out_leftover[i], dest_buf[i]) << " at " << i;
-  FX_Free(dest_buf);
+    // Check the output
+    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+    for (uint32_t i = 0; i < dest_size; i++)
+      EXPECT_EQ(expected_out_leftover[i], dest_buf_span[i]) << " at " << i;
+  }
 }
 
 // Make sure we get returns in the expected locations.
@@ -175,7 +182,7 @@
     src_buf[k + 2] = 3;
     src_buf[k + 3] = 4;
   }
-  uint8_t* dest_buf = nullptr;
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
   uint32_t dest_size = 0;
 
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
@@ -190,10 +197,9 @@
   ASSERT_EQ(166u, dest_size);
 
   // Check for the returns.
-  EXPECT_EQ(13, dest_buf[75]);
-  EXPECT_EQ(10, dest_buf[76]);
-  EXPECT_EQ(13, dest_buf[153]);
-  EXPECT_EQ(10, dest_buf[154]);
-
-  FX_Free(dest_buf);
+  auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+  EXPECT_EQ(13, dest_buf_span[75]);
+  EXPECT_EQ(10, dest_buf_span[76]);
+  EXPECT_EQ(13, dest_buf_span[153]);
+  EXPECT_EQ(10, dest_buf_span[154]);
 }
diff --git a/core/fxcodec/codec/fx_codec_rle_unittest.cpp b/core/fxcodec/codec/fx_codec_rle_unittest.cpp
index 3ee0aa6..433d96d 100644
--- a/core/fxcodec/codec/fx_codec_rle_unittest.cpp
+++ b/core/fxcodec/codec/fx_codec_rle_unittest.cpp
@@ -14,7 +14,7 @@
 
 TEST(fxcodec, RLETestBadInputs) {
   const uint8_t src_buf[] = {1};
-  uint8_t* dest_buf = nullptr;
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
   uint32_t dest_size = 0;
 
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
@@ -28,145 +28,144 @@
 
 // Check length 1 input works. Check terminating character is applied.
 TEST(fxcodec, RLETestShortInput) {
-  const uint8_t src_buf[] = {1};
-  uint8_t* dest_buf = nullptr;
-  uint32_t dest_size = 0;
-
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
   EXPECT_TRUE(pEncoders);
 
+  const uint8_t src_buf[] = {1};
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
+  uint32_t dest_size = 0;
+
   EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf, &dest_buf, &dest_size));
   ASSERT_EQ(3u, dest_size);
-  EXPECT_EQ(0, dest_buf[0]);
-  EXPECT_EQ(1, dest_buf[1]);
-  EXPECT_EQ(128, dest_buf[2]);
-
-  FX_Free(dest_buf);
+  auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
+  EXPECT_EQ(0, dest_buf_span[0]);
+  EXPECT_EQ(1, dest_buf_span[1]);
+  EXPECT_EQ(128, dest_buf_span[2]);
 }
 
 // Check a few basic cases (2 matching runs in a row, matching run followed
 // by a non-matching run, and non-matching run followed by a matching run).
 TEST(fxcodec, RLETestNormalInputs) {
-  // Match, match
-  const uint8_t src_buf_1[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4};
-
-  // Match, non-match
-  const uint8_t src_buf_2[] = {2, 2, 2, 2, 1, 2, 3, 4, 5, 6};
-
-  // Non-match, match
-  const uint8_t src_buf_3[] = {1, 2, 3, 4, 5, 3, 3, 3, 3, 3};
-
-  uint32_t dest_size = 0;
-  uint8_t* dest_buf = nullptr;
-
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
   EXPECT_TRUE(pEncoders);
 
-  // Case 1:
-  EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_1, &dest_buf, &dest_size));
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
+  uint32_t dest_size = 0;
   std::unique_ptr<uint8_t, FxFreeDeleter> decoded_buf;
   uint32_t decoded_size = 0;
-  RunLengthDecode({dest_buf, dest_size}, &decoded_buf, &decoded_size);
-  ASSERT_EQ(sizeof(src_buf_1), decoded_size);
-  for (uint32_t i = 0; i < decoded_size; i++)
-    EXPECT_EQ(src_buf_1[i], decoded_buf.get()[i]) << " at " << i;
-  FX_Free(dest_buf);
 
-  // Case 2:
-  dest_buf = nullptr;
-  dest_size = 0;
-  EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_2, &dest_buf, &dest_size));
-  decoded_buf.reset();
-  decoded_size = 0;
-  RunLengthDecode({dest_buf, dest_size}, &decoded_buf, &decoded_size);
-  ASSERT_EQ(sizeof(src_buf_2), decoded_size);
-  for (uint32_t i = 0; i < decoded_size; i++)
-    EXPECT_EQ(src_buf_2[i], decoded_buf.get()[i]) << " at " << i;
-  FX_Free(dest_buf);
+  {
+    // Case 1: Match, match
+    const uint8_t src_buf_1[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4};
+    EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_1, &dest_buf, &dest_size));
+    RunLengthDecode({dest_buf.get(), dest_size}, &decoded_buf, &decoded_size);
+    ASSERT_EQ(sizeof(src_buf_1), decoded_size);
+    auto decoded_buf_span = pdfium::make_span(decoded_buf.get(), decoded_size);
+    for (uint32_t i = 0; i < decoded_size; i++)
+      EXPECT_EQ(src_buf_1[i], decoded_buf_span[i]) << " at " << i;
+  }
 
-  // Case 3:
-  dest_buf = nullptr;
-  dest_size = 0;
-  EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_3, &dest_buf, &dest_size));
-  decoded_buf.reset();
-  decoded_size = 0;
-  RunLengthDecode({dest_buf, dest_size}, &decoded_buf, &decoded_size);
-  ASSERT_EQ(sizeof(src_buf_3), decoded_size);
-  for (uint32_t i = 0; i < decoded_size; i++)
-    EXPECT_EQ(src_buf_3[i], decoded_buf.get()[i]) << " at " << i;
-  FX_Free(dest_buf);
+  {
+    // Case 2: Match, non-match
+    const uint8_t src_buf_2[] = {2, 2, 2, 2, 1, 2, 3, 4, 5, 6};
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_2, &dest_buf, &dest_size));
+    decoded_buf.reset();
+    decoded_size = 0;
+    RunLengthDecode({dest_buf.get(), dest_size}, &decoded_buf, &decoded_size);
+    ASSERT_EQ(sizeof(src_buf_2), decoded_size);
+    auto decoded_buf_span = pdfium::make_span(decoded_buf.get(), decoded_size);
+    for (uint32_t i = 0; i < decoded_size; i++)
+      EXPECT_EQ(src_buf_2[i], decoded_buf_span[i]) << " at " << i;
+  }
+
+  {
+    // Case 3: Non-match, match
+    const uint8_t src_buf_3[] = {1, 2, 3, 4, 5, 3, 3, 3, 3, 3};
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_3, &dest_buf, &dest_size));
+    decoded_buf.reset();
+    decoded_size = 0;
+    RunLengthDecode({dest_buf.get(), dest_size}, &decoded_buf, &decoded_size);
+    ASSERT_EQ(sizeof(src_buf_3), decoded_size);
+    auto decoded_buf_span = pdfium::make_span(decoded_buf.get(), decoded_size);
+    for (uint32_t i = 0; i < decoded_size; i++)
+      EXPECT_EQ(src_buf_3[i], decoded_buf_span[i]) << " at " << i;
+  }
 }
 
 // Check that runs longer than 128 are broken up properly, both matched and
 // non-matched.
 TEST(fxcodec, RLETestFullLengthInputs) {
-  // Match, match
-  const uint8_t src_buf_1[260] = {1};
-
-  // Match, non-match
-  uint8_t src_buf_2[260] = {2};
-  for (uint16_t i = 128; i < 260; i++)
-    src_buf_2[i] = (uint8_t)(i - 125);
-
-  // Non-match, match
-  uint8_t src_buf_3[260] = {3};
-  for (uint8_t i = 0; i < 128; i++)
-    src_buf_3[i] = i;
-
-  // Non-match, non-match
-  uint8_t src_buf_4[260];
-  for (uint16_t i = 0; i < 260; i++)
-    src_buf_4[i] = (uint8_t)(i);
-
-  uint32_t dest_size = 0;
-  uint8_t* dest_buf = nullptr;
-
   CCodec_BasicModule* pEncoders = CCodec_ModuleMgr().GetBasicModule();
   EXPECT_TRUE(pEncoders);
 
-  // Case 1:
-  EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_1, &dest_buf, &dest_size));
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
+  uint32_t dest_size = 0;
   std::unique_ptr<uint8_t, FxFreeDeleter> decoded_buf;
   uint32_t decoded_size = 0;
-  RunLengthDecode({dest_buf, dest_size}, &decoded_buf, &decoded_size);
-  ASSERT_EQ(sizeof(src_buf_1), decoded_size);
-  for (uint32_t i = 0; i < decoded_size; i++)
-    EXPECT_EQ(src_buf_1[i], decoded_buf.get()[i]) << " at " << i;
-  FX_Free(dest_buf);
 
-  // Case 2:
-  dest_buf = nullptr;
-  dest_size = 0;
-  EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_2, &dest_buf, &dest_size));
-  decoded_buf.reset();
-  decoded_size = 0;
-  RunLengthDecode({dest_buf, dest_size}, &decoded_buf, &decoded_size);
-  ASSERT_EQ(sizeof(src_buf_2), decoded_size);
-  for (uint32_t i = 0; i < decoded_size; i++)
-    EXPECT_EQ(src_buf_2[i], decoded_buf.get()[i]) << " at " << i;
-  FX_Free(dest_buf);
+  {
+    // Case 1: Match, match
+    const uint8_t src_buf_1[260] = {1};
+    EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_1, &dest_buf, &dest_size));
+    RunLengthDecode({dest_buf.get(), dest_size}, &decoded_buf, &decoded_size);
+    ASSERT_EQ(sizeof(src_buf_1), decoded_size);
+    auto decoded_buf_span = pdfium::make_span(decoded_buf.get(), decoded_size);
+    for (uint32_t i = 0; i < decoded_size; i++)
+      EXPECT_EQ(src_buf_1[i], decoded_buf_span[i]) << " at " << i;
+  }
 
-  // Case 3:
-  dest_buf = nullptr;
-  dest_size = 0;
-  EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_3, &dest_buf, &dest_size));
-  decoded_buf.reset();
-  decoded_size = 0;
-  RunLengthDecode({dest_buf, dest_size}, &decoded_buf, &decoded_size);
-  ASSERT_EQ(sizeof(src_buf_3), decoded_size);
-  for (uint32_t i = 0; i < decoded_size; i++)
-    EXPECT_EQ(src_buf_3[i], decoded_buf.get()[i]) << " at " << i;
-  FX_Free(dest_buf);
+  {
+    // Case 2: Match, non-match
+    uint8_t src_buf_2[260] = {2};
+    for (uint16_t i = 128; i < 260; i++)
+      src_buf_2[i] = static_cast<uint8_t>(i - 125);
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_2, &dest_buf, &dest_size));
+    decoded_buf.reset();
+    decoded_size = 0;
+    RunLengthDecode({dest_buf.get(), dest_size}, &decoded_buf, &decoded_size);
+    ASSERT_EQ(sizeof(src_buf_2), decoded_size);
+    auto decoded_buf_span = pdfium::make_span(decoded_buf.get(), decoded_size);
+    for (uint32_t i = 0; i < decoded_size; i++)
+      EXPECT_EQ(src_buf_2[i], decoded_buf_span[i]) << " at " << i;
+  }
 
-  // Case 4:
-  dest_buf = nullptr;
-  dest_size = 0;
-  EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_4, &dest_buf, &dest_size));
-  decoded_buf.reset();
-  decoded_size = 0;
-  RunLengthDecode({dest_buf, dest_size}, &decoded_buf, &decoded_size);
-  ASSERT_EQ(sizeof(src_buf_4), decoded_size);
-  for (uint32_t i = 0; i < decoded_size; i++)
-    EXPECT_EQ(src_buf_4[i], decoded_buf.get()[i]) << " at " << i;
-  FX_Free(dest_buf);
+  {
+    // Case 3: Non-match, match
+    uint8_t src_buf_3[260] = {3};
+    for (uint8_t i = 0; i < 128; i++)
+      src_buf_3[i] = i;
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_3, &dest_buf, &dest_size));
+    decoded_buf.reset();
+    decoded_size = 0;
+    RunLengthDecode({dest_buf.get(), dest_size}, &decoded_buf, &decoded_size);
+    ASSERT_EQ(sizeof(src_buf_3), decoded_size);
+    auto decoded_buf_span = pdfium::make_span(decoded_buf.get(), decoded_size);
+    for (uint32_t i = 0; i < decoded_size; i++)
+      EXPECT_EQ(src_buf_3[i], decoded_buf_span[i]) << " at " << i;
+  }
+
+  {
+    // Case 4: Non-match, non-match
+    uint8_t src_buf_4[260];
+    for (uint16_t i = 0; i < 260; i++)
+      src_buf_4[i] = static_cast<uint8_t>(i);
+    dest_buf.reset();
+    dest_size = 0;
+    EXPECT_TRUE(pEncoders->RunLengthEncode(src_buf_4, &dest_buf, &dest_size));
+    decoded_buf.reset();
+    decoded_size = 0;
+    RunLengthDecode({dest_buf.get(), dest_size}, &decoded_buf, &decoded_size);
+    ASSERT_EQ(sizeof(src_buf_4), decoded_size);
+    auto decoded_buf_span = pdfium::make_span(decoded_buf.get(), decoded_size);
+    for (uint32_t i = 0; i < decoded_size; i++)
+      EXPECT_EQ(src_buf_4[i], decoded_buf_span[i]) << " at " << i;
+  }
 }
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index e66e968..11acfc8 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -66,8 +66,10 @@
       *filter = "/FlateDecode filter ";
     }
   } else {
-    if (pEncoders->GetBasicModule()->RunLengthEncode({src_buf, src_size},
-                                                     &dest_buf, &dest_size)) {
+    std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf_unique;
+    if (pEncoders->GetBasicModule()->RunLengthEncode(
+            {src_buf, src_size}, &dest_buf_unique, &dest_size)) {
+      dest_buf = dest_buf_unique.release();
       *filter = "/RunLengthDecode filter ";
     }
   }
@@ -685,13 +687,12 @@
 }
 
 void CFX_PSRenderer::WritePSBinary(const uint8_t* data, int len) {
-  uint8_t* dest_buf;
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
   uint32_t dest_size;
   CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule();
   if (pEncoders->GetBasicModule()->A85Encode({data, static_cast<size_t>(len)},
                                              &dest_buf, &dest_size)) {
-    m_pStream->WriteBlock(dest_buf, dest_size);
-    FX_Free(dest_buf);
+    m_pStream->WriteBlock(dest_buf.get(), dest_size);
   } else {
     m_pStream->WriteBlock(data, len);
   }
diff --git a/testing/fuzzers/pdf_codec_a85_fuzzer.cc b/testing/fuzzers/pdf_codec_a85_fuzzer.cc
index 0da713b..e45b81f 100644
--- a/testing/fuzzers/pdf_codec_a85_fuzzer.cc
+++ b/testing/fuzzers/pdf_codec_a85_fuzzer.cc
@@ -9,10 +9,9 @@
 #include "core/fxcrt/fx_memory.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  uint8_t* dest_buf = nullptr;
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
   uint32_t dest_size = 0;
   CCodec_BasicModule encoder_module;
   encoder_module.A85Encode({data, size}, &dest_buf, &dest_size);
-  FX_Free(dest_buf);
   return 0;
 }
diff --git a/testing/fuzzers/pdf_codec_rle_fuzzer.cc b/testing/fuzzers/pdf_codec_rle_fuzzer.cc
index adf454e..13c4a48 100644
--- a/testing/fuzzers/pdf_codec_rle_fuzzer.cc
+++ b/testing/fuzzers/pdf_codec_rle_fuzzer.cc
@@ -9,10 +9,9 @@
 #include "core/fxcrt/fx_memory.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  uint8_t* dest_buf = nullptr;
+  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
   uint32_t dest_size = 0;
   CCodec_BasicModule encoder_module;
   encoder_module.RunLengthEncode({data, size}, &dest_buf, &dest_size);
-  FX_Free(dest_buf);
   return 0;
 }