[res] Zero big buffer memory on backing up

When a memory chunk gets returned into BigBuffer, it may have
some data written already. BigBuffer is supposed to give out
zeroed memory, so BackUp() needs to zero it as well

Bug: 336758568
Bug: 342579978
Test: unit test + bundletool on the attached aab
Flag: EXEMPT bugfix
Change-Id: I8ecd60e84dbe16570a92d82370d1633af72599c8
diff --git a/libs/androidfw/BigBuffer.cpp b/libs/androidfw/BigBuffer.cpp
index bedfc49..43b56c3 100644
--- a/libs/androidfw/BigBuffer.cpp
+++ b/libs/androidfw/BigBuffer.cpp
@@ -17,8 +17,8 @@
 #include <androidfw/BigBuffer.h>
 
 #include <algorithm>
+#include <iterator>
 #include <memory>
-#include <vector>
 
 #include "android-base/logging.h"
 
@@ -78,10 +78,27 @@
 
 std::string BigBuffer::to_string() const {
   std::string result;
+  result.reserve(size_);
   for (const Block& block : blocks_) {
     result.append(block.buffer.get(), block.buffer.get() + block.size);
   }
   return result;
 }
 
+void BigBuffer::AppendBuffer(BigBuffer&& buffer) {
+  std::move(buffer.blocks_.begin(), buffer.blocks_.end(), std::back_inserter(blocks_));
+  size_ += buffer.size_;
+  buffer.blocks_.clear();
+  buffer.size_ = 0;
+}
+
+void BigBuffer::BackUp(size_t count) {
+  Block& block = blocks_.back();
+  block.size -= count;
+  size_ -= count;
+  // BigBuffer is supposed to always give zeroed memory, but backing up usually means
+  // something has been already written into the block. Erase it.
+  std::fill_n(block.buffer.get() + block.size, count, 0);
+}
+
 }  // namespace android
diff --git a/libs/androidfw/include/androidfw/BigBuffer.h b/libs/androidfw/include/androidfw/BigBuffer.h
index b99a4ed..c4cd7c5 100644
--- a/libs/androidfw/include/androidfw/BigBuffer.h
+++ b/libs/androidfw/include/androidfw/BigBuffer.h
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef _ANDROID_BIG_BUFFER_H
-#define _ANDROID_BIG_BUFFER_H
+#pragma once
 
-#include <cstring>
 #include <memory>
 #include <string>
 #include <type_traits>
+#include <utility>
 #include <vector>
 
 #include "android-base/logging.h"
@@ -150,24 +149,11 @@
 
 template <typename T>
 inline T* BigBuffer::NextBlock(size_t count) {
-  static_assert(std::is_standard_layout<T>::value, "T must be standard_layout type");
+  static_assert(std::is_standard_layout_v<T>, "T must be standard_layout type");
   CHECK(count != 0);
   return reinterpret_cast<T*>(NextBlockImpl(sizeof(T) * count));
 }
 
-inline void BigBuffer::BackUp(size_t count) {
-  Block& block = blocks_.back();
-  block.size -= count;
-  size_ -= count;
-}
-
-inline void BigBuffer::AppendBuffer(BigBuffer&& buffer) {
-  std::move(buffer.blocks_.begin(), buffer.blocks_.end(), std::back_inserter(blocks_));
-  size_ += buffer.size_;
-  buffer.blocks_.clear();
-  buffer.size_ = 0;
-}
-
 inline void BigBuffer::Pad(size_t bytes) {
   NextBlock<char>(bytes);
 }
@@ -188,5 +174,3 @@
 }
 
 }  // namespace android
-
-#endif  // _ANDROID_BIG_BUFFER_H
diff --git a/libs/androidfw/tests/BigBuffer_test.cpp b/libs/androidfw/tests/BigBuffer_test.cpp
index 382d21e..7e38f17 100644
--- a/libs/androidfw/tests/BigBuffer_test.cpp
+++ b/libs/androidfw/tests/BigBuffer_test.cpp
@@ -98,4 +98,20 @@
   ASSERT_EQ(8u, buffer.size());
 }
 
+TEST(BigBufferTest, BackUpZeroed) {
+  BigBuffer buffer(16);
+
+  auto block = buffer.NextBlock<char>(2);
+  ASSERT_TRUE(block != nullptr);
+  ASSERT_EQ(2u, buffer.size());
+  block[0] = 0x01;
+  block[1] = 0x02;
+  buffer.BackUp(1);
+  ASSERT_EQ(1u, buffer.size());
+  auto new_block = buffer.NextBlock<char>(1);
+  ASSERT_TRUE(new_block != nullptr);
+  ASSERT_EQ(2u, buffer.size());
+  ASSERT_EQ(0, *new_block);
+}
+
 }  // namespace android