Home | History | Annotate | Download | only in protozero
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "perfetto/protozero/message.h"
     18 #include "perfetto/protozero/message_handle.h"
     19 
     20 #include <limits>
     21 #include <memory>
     22 #include <utility>
     23 #include <vector>
     24 
     25 #include "gtest/gtest.h"
     26 #include "perfetto/base/logging.h"
     27 #include "src/protozero/test/fake_scattered_buffer.h"
     28 
     29 namespace protozero {
     30 
     31 namespace {
     32 
     33 constexpr size_t kChunkSize = 16;
     34 constexpr uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0};
     35 constexpr const char kStartWatermark[] = {'a', 'b', 'c', 'd',
     36                                           '1', '2', '3', '\0'};
     37 constexpr const char kEndWatermark[] = {'9', '8', '7', '6',
     38                                         'z', 'w', 'y', '\0'};
     39 
     40 class FakeRootMessage : public Message {};
     41 class FakeChildMessage : public Message {};
     42 
     43 uint32_t SimpleHash(const std::string& str) {
     44   uint32_t hash = 5381;
     45   for (char c : str)
     46     hash = 33 * hash + static_cast<uint32_t>(c);
     47   return hash;
     48 }
     49 
     50 class MessageTest : public ::testing::Test {
     51  public:
     52   void SetUp() override {
     53     buffer_.reset(new FakeScatteredBuffer(kChunkSize));
     54     stream_writer_.reset(new ScatteredStreamWriter(buffer_.get()));
     55     readback_pos_ = 0;
     56   }
     57 
     58   void TearDown() override {
     59     // Check that none of the messages created by the text fixtures below did
     60     // under/overflow their heap boundaries.
     61     for (std::unique_ptr<uint8_t[]>& mem : messages_) {
     62       EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
     63       EXPECT_STREQ(kEndWatermark,
     64                    reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
     65                                            sizeof(Message)));
     66       mem.reset();
     67     }
     68     messages_.clear();
     69     stream_writer_.reset();
     70     buffer_.reset();
     71   }
     72 
     73   void ResetMessage(FakeRootMessage* msg) { msg->Reset(stream_writer_.get()); }
     74 
     75   FakeRootMessage* NewMessage() {
     76     std::unique_ptr<uint8_t[]> mem(
     77         new uint8_t[sizeof(kStartWatermark) + sizeof(FakeRootMessage) +
     78                     sizeof(kEndWatermark)]);
     79     uint8_t* msg_start = mem.get() + sizeof(kStartWatermark);
     80     memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark));
     81     memset(msg_start, 0, sizeof(FakeRootMessage));
     82     memcpy(msg_start + sizeof(FakeRootMessage), kEndWatermark,
     83            sizeof(kEndWatermark));
     84     messages_.push_back(std::move(mem));
     85     FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(msg_start);
     86     msg->Reset(stream_writer_.get());
     87     return msg;
     88   }
     89 
     90   size_t GetNumSerializedBytes() {
     91     if (buffer_->chunks().empty())
     92       return 0;
     93     return buffer_->chunks().size() * kChunkSize -
     94            stream_writer_->bytes_available();
     95   }
     96 
     97   std::string GetNextSerializedBytes(size_t num_bytes) {
     98     size_t old_readback_pos = readback_pos_;
     99     readback_pos_ += num_bytes;
    100     return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
    101   }
    102 
    103   static void BuildNestedMessages(Message* msg, uint32_t depth = 0) {
    104     for (uint32_t i = 1; i <= 128; ++i)
    105       msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
    106 
    107     if (depth < Message::kMaxNestingDepth) {
    108       auto* nested_msg =
    109           msg->BeginNestedMessage<FakeChildMessage>(1 + depth * 10);
    110       BuildNestedMessages(nested_msg, depth + 1);
    111     }
    112 
    113     for (uint32_t i = 129; i <= 256; ++i)
    114       msg->AppendVarInt(i, 42);
    115 
    116     if ((depth & 2) == 0)
    117       msg->Finalize();
    118   }
    119 
    120  private:
    121   std::unique_ptr<FakeScatteredBuffer> buffer_;
    122   std::unique_ptr<ScatteredStreamWriter> stream_writer_;
    123   std::vector<std::unique_ptr<uint8_t[]>> messages_;
    124   size_t readback_pos_;
    125 };
    126 
    127 TEST_F(MessageTest, ZeroLengthArraysAndStrings) {
    128   Message* msg = NewMessage();
    129   msg->AppendBytes(1 /* field_id */, nullptr, 0);
    130   msg->AppendString(2 /* field_id */, "");
    131 
    132   EXPECT_EQ(4u, msg->Finalize());
    133   EXPECT_EQ(4u, GetNumSerializedBytes());
    134 
    135   // These lines match the serialization of the Append* calls above.
    136   ASSERT_EQ("0A00", GetNextSerializedBytes(2));
    137   ASSERT_EQ("1200", GetNextSerializedBytes(2));
    138 }
    139 
    140 TEST_F(MessageTest, BasicTypesNoNesting) {
    141   Message* msg = NewMessage();
    142   msg->AppendVarInt(1 /* field_id */, 0);
    143   msg->AppendVarInt(2 /* field_id */, std::numeric_limits<uint32_t>::max());
    144   msg->AppendVarInt(3 /* field_id */, 42);
    145   msg->AppendVarInt(4 /* field_id */, std::numeric_limits<uint64_t>::max());
    146   msg->AppendFixed(5 /* field_id */, 3.1415f /* float */);
    147   msg->AppendFixed(6 /* field_id */, 3.14159265358979323846 /* double */);
    148   msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes));
    149 
    150   // Field ids > 16 are expected to be varint encoded (preamble > 1 byte)
    151   msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF");
    152   msg->AppendSignedVarInt(3 /* field_id */, -21);
    153 
    154   EXPECT_EQ(74u, msg->Finalize());
    155   EXPECT_EQ(74u, GetNumSerializedBytes());
    156 
    157   // These lines match the serialization of the Append* calls above.
    158   ASSERT_EQ("0800", GetNextSerializedBytes(2));
    159   ASSERT_EQ("10FFFFFFFF0F", GetNextSerializedBytes(6));
    160   ASSERT_EQ("182A", GetNextSerializedBytes(2));
    161   ASSERT_EQ("20FFFFFFFFFFFFFFFFFF01", GetNextSerializedBytes(11));
    162   ASSERT_EQ("2D560E4940", GetNextSerializedBytes(5));
    163   ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9));
    164   ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12));
    165   ASSERT_EQ("8A101630313233343536373839616263646566414243444546",
    166             GetNextSerializedBytes(25));
    167   ASSERT_EQ("1829", GetNextSerializedBytes(2));
    168 }
    169 
    170 TEST_F(MessageTest, NestedMessagesSimple) {
    171   Message* root_msg = NewMessage();
    172   root_msg->AppendVarInt(1 /* field_id */, 1);
    173 
    174   FakeChildMessage* nested_msg =
    175       root_msg->BeginNestedMessage<FakeChildMessage>(128 /* field_id */);
    176   ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*));
    177   nested_msg->AppendVarInt(2 /* field_id */, 2);
    178 
    179   nested_msg =
    180       root_msg->BeginNestedMessage<FakeChildMessage>(129 /* field_id */);
    181   nested_msg->AppendVarInt(4 /* field_id */, 2);
    182 
    183   root_msg->AppendVarInt(5 /* field_id */, 3);
    184 
    185   // The expected size of the root message is supposed to be 20 bytes:
    186   //   2 bytes for the varint field (id: 1) (1 for preamble and one for payload)
    187   //   6 bytes for the preamble of the 1st nested message (2 for id, 4 for size)
    188   //   2 bytes for the varint field (id: 2) of the 1st nested message
    189   //   6 bytes for the premable of the 2nd nested message
    190   //   2 bytes for the varint field (id: 4) of the 2nd nested message.
    191   //   2 bytes for the last varint (id : 5) field of the root message.
    192   // Test also that finalization is idempontent and Finalize() can be safely
    193   // called more than once without side effects.
    194   for (int i = 0; i < 3; ++i) {
    195     EXPECT_EQ(20u, root_msg->Finalize());
    196     EXPECT_EQ(20u, GetNumSerializedBytes());
    197   }
    198 
    199   ASSERT_EQ("0801", GetNextSerializedBytes(2));
    200 
    201   ASSERT_EQ("820882808000", GetNextSerializedBytes(6));
    202   ASSERT_EQ("1002", GetNextSerializedBytes(2));
    203 
    204   ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6));
    205   ASSERT_EQ("2002", GetNextSerializedBytes(2));
    206 
    207   ASSERT_EQ("2803", GetNextSerializedBytes(2));
    208 }
    209 
    210 // Checks that the size field of root and nested messages is properly written
    211 // on finalization.
    212 TEST_F(MessageTest, BackfillSizeOnFinalization) {
    213   Message* root_msg = NewMessage();
    214   uint8_t root_msg_size[proto_utils::kMessageLengthFieldSize] = {};
    215   root_msg->set_size_field(&root_msg_size[0]);
    216   root_msg->AppendVarInt(1, 0x42);
    217 
    218   FakeChildMessage* nested_msg_1 =
    219       root_msg->BeginNestedMessage<FakeChildMessage>(2);
    220   nested_msg_1->AppendVarInt(3, 0x43);
    221 
    222   FakeChildMessage* nested_msg_2 =
    223       nested_msg_1->BeginNestedMessage<FakeChildMessage>(4);
    224   uint8_t buf200[200];
    225   memset(buf200, 0x42, sizeof(buf200));
    226   nested_msg_2->AppendBytes(5, buf200, sizeof(buf200));
    227 
    228   root_msg->inc_size_already_written(6);
    229 
    230   // The value returned by Finalize() should be == the full size of |root_msg|.
    231   EXPECT_EQ(217u, root_msg->Finalize());
    232   EXPECT_EQ(217u, GetNumSerializedBytes());
    233 
    234   // However the size written in the size field should take into account the
    235   // inc_size_already_written() call and be equal to 118 - 6 = 112, encoded
    236   // in a rendundant varint encoding of kMessageLengthFieldSize bytes.
    237   EXPECT_STREQ("\xD3\x81\x80\x00", reinterpret_cast<char*>(root_msg_size));
    238 
    239   // Skip 2 bytes for the 0x42 varint + 1 byte for the |nested_msg_1| preamble.
    240   GetNextSerializedBytes(3);
    241 
    242   // Check that the size of |nested_msg_1| was backfilled. Its size is:
    243   // 203 bytes for |nest_mesg_2| (see below) + 5 bytes for its preamble +
    244   // 2 bytes for the 0x43 varint = 210 bytes.
    245   EXPECT_EQ("D2818000", GetNextSerializedBytes(4));
    246 
    247   // Skip 2 bytes for the 0x43 varint + 1 byte for the |nested_msg_2| preamble.
    248   GetNextSerializedBytes(3);
    249 
    250   // Check that the size of |nested_msg_2| was backfilled. Its size is:
    251   // 200 bytes (for |buf200|) + 3 bytes for its preamble = 203 bytes.
    252   EXPECT_EQ("CB818000", GetNextSerializedBytes(4));
    253 }
    254 
    255 TEST_F(MessageTest, StressTest) {
    256   std::vector<Message*> nested_msgs;
    257 
    258   Message* root_msg = NewMessage();
    259   BuildNestedMessages(root_msg);
    260   root_msg->Finalize();
    261 
    262   // The main point of this test is to stress the code paths and test for
    263   // unexpected crashes of the production code. The actual serialization is
    264   // already covered in the other text fixtures. Keeping just a final smoke test
    265   // here on the full buffer hash.
    266   std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
    267   size_t buf_hash = SimpleHash(full_buf);
    268   EXPECT_EQ(0xfd19cc0a, buf_hash);
    269 }
    270 
    271 TEST_F(MessageTest, DestructInvalidMessageHandle) {
    272   FakeRootMessage* msg = NewMessage();
    273   EXPECT_DEBUG_DEATH(
    274       {
    275         MessageHandle<FakeRootMessage> handle(msg);
    276         ResetMessage(msg);
    277       },
    278       "");
    279 }
    280 
    281 TEST_F(MessageTest, MessageHandle) {
    282   FakeRootMessage* msg1 = NewMessage();
    283   FakeRootMessage* msg2 = NewMessage();
    284   FakeRootMessage* msg3 = NewMessage();
    285   FakeRootMessage* ignored_msg = NewMessage();
    286   uint8_t msg1_size[proto_utils::kMessageLengthFieldSize] = {};
    287   uint8_t msg2_size[proto_utils::kMessageLengthFieldSize] = {};
    288   uint8_t msg3_size[proto_utils::kMessageLengthFieldSize] = {};
    289   msg1->set_size_field(&msg1_size[0]);
    290   msg2->set_size_field(&msg2_size[0]);
    291   msg3->set_size_field(&msg3_size[0]);
    292 
    293   // Test that the handle going out of scope causes the finalization of the
    294   // target message and triggers the optional callback.
    295   {
    296     MessageHandle<FakeRootMessage> handle1(msg1);
    297     handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
    298     ASSERT_EQ(0u, msg1_size[0]);
    299   }
    300   ASSERT_EQ(0x83u, msg1_size[0]);
    301 
    302   // Test that the handle can be late initialized.
    303   MessageHandle<FakeRootMessage> handle2(ignored_msg);
    304   handle2 = MessageHandle<FakeRootMessage>(msg2);
    305   handle2->AppendBytes(1 /* field_id */, kTestBytes, 2 /* size */);
    306   ASSERT_EQ(0u, msg2_size[0]);  // |msg2| should not be finalized yet.
    307 
    308   // Test that std::move works and does NOT cause finalization of the moved
    309   // message.
    310   MessageHandle<FakeRootMessage> handle_swp(ignored_msg);
    311   handle_swp = std::move(handle2);
    312   ASSERT_EQ(0u, msg2_size[0]);  // msg2 should be NOT finalized yet.
    313   handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 3 /* size */);
    314 
    315   MessageHandle<FakeRootMessage> handle3(msg3);
    316   handle3->AppendBytes(1 /* field_id */, kTestBytes, 4 /* size */);
    317   ASSERT_EQ(0u, msg3_size[0]);  // msg2 should be NOT finalized yet.
    318 
    319   // Both |handle3| and |handle_swp| point to a valid message (respectively,
    320   // |msg3| and |msg2|). Now move |handle3| into |handle_swp|.
    321   handle_swp = std::move(handle3);
    322   ASSERT_EQ(0x89u, msg2_size[0]);  // |msg2| should be finalized at this point.
    323 
    324   // At this point writing into handle_swp should actually write into |msg3|.
    325   ASSERT_EQ(msg3, &*handle_swp);
    326   handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 8 /* size */);
    327   MessageHandle<FakeRootMessage> another_handle(ignored_msg);
    328   handle_swp = std::move(another_handle);
    329   ASSERT_EQ(0x90u, msg3_size[0]);  // |msg3| should be finalized at this point.
    330 
    331 #if PERFETTO_DCHECK_IS_ON()
    332   // In developer builds w/ PERFETTO_DCHECK on a finalized message should
    333   // invalidate the handle, in order to early catch bugs in the client code.
    334   FakeRootMessage* msg4 = NewMessage();
    335   MessageHandle<FakeRootMessage> handle4(msg4);
    336   ASSERT_EQ(msg4, &*handle4);
    337   msg4->Finalize();
    338   ASSERT_EQ(nullptr, &*handle4);
    339 #endif
    340 
    341   // Test also the behavior of handle with non-root (nested) messages.
    342 
    343   uint8_t* size_msg_2;
    344   {
    345     auto* nested_msg_1 = NewMessage()->BeginNestedMessage<FakeChildMessage>(3);
    346     MessageHandle<FakeChildMessage> child_handle_1(nested_msg_1);
    347     uint8_t* size_msg_1 = nested_msg_1->size_field();
    348     memset(size_msg_1, 0, proto_utils::kMessageLengthFieldSize);
    349     child_handle_1->AppendVarInt(1, 0x11);
    350 
    351     auto* nested_msg_2 = NewMessage()->BeginNestedMessage<FakeChildMessage>(2);
    352     size_msg_2 = nested_msg_2->size_field();
    353     memset(size_msg_2, 0, proto_utils::kMessageLengthFieldSize);
    354     MessageHandle<FakeChildMessage> child_handle_2(nested_msg_2);
    355     child_handle_2->AppendVarInt(2, 0xFF);
    356 
    357     // |nested_msg_1| should not be finalized yet.
    358     ASSERT_EQ(0u, size_msg_1[0]);
    359 
    360     // This move should cause |nested_msg_1| to be finalized, but not
    361     // |nested_msg_2|, which will be finalized only after the current scope.
    362     child_handle_1 = std::move(child_handle_2);
    363     ASSERT_EQ(0x82u, size_msg_1[0]);
    364     ASSERT_EQ(0u, size_msg_2[0]);
    365   }
    366   ASSERT_EQ(0x83u, size_msg_2[0]);
    367 }
    368 
    369 TEST_F(MessageTest, MoveMessageHandle) {
    370   FakeRootMessage* msg = NewMessage();
    371   uint8_t msg_size[proto_utils::kMessageLengthFieldSize] = {};
    372   msg->set_size_field(&msg_size[0]);
    373 
    374   // Test that the handle going out of scope causes the finalization of the
    375   // target message.
    376   {
    377     MessageHandle<FakeRootMessage> handle1(msg);
    378     MessageHandle<FakeRootMessage> handle2{};
    379     handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
    380     handle2 = std::move(handle1);
    381     ASSERT_EQ(0u, msg_size[0]);
    382   }
    383   ASSERT_EQ(0x83u, msg_size[0]);
    384 }
    385 
    386 }  // namespace
    387 }  // namespace protozero
    388