mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-26 23:01:05 +08:00
8071d3019e
This CL cleans up types and code style comments from post-submit code review comments on https://crrev.com/c/4023618 . I also added fixes for potential overflows in varint length decoding and included new tests. Bug: crashpad:437 Change-Id: I0a3585036028d81f42d0d36e87cce4264f4ed9ad Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4199705 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
349 lines
13 KiB
C++
349 lines
13 KiB
C++
// Copyright 2023 The Crashpad Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "client/length_delimited_ring_buffer.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <array>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace crashpad {
|
|
namespace test {
|
|
namespace {
|
|
|
|
using testing::Eq;
|
|
using testing::IsFalse;
|
|
using testing::IsTrue;
|
|
|
|
// Buffer with magic 0xcab00d1e, version 1, read_pos 0, length 3, and 3 bytes of
|
|
// data (1 varint length, 2 bytes data)
|
|
constexpr char kValidBufferSize3[] =
|
|
"\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x02\x42"
|
|
"\x23";
|
|
constexpr size_t kValidBufferSize3Len =
|
|
sizeof(kValidBufferSize3) - 1; // Remove trailing NUL.
|
|
|
|
// Buffer with magic 0xcab00d1e, version 8, read_pos 0, length 3, and 3 bytes of
|
|
// data (1 varint length, 2 bytes data).
|
|
constexpr char kInvalidVersionBuffer[] =
|
|
"\x1e\x0d\xb0\xca\x08\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x02\xab"
|
|
"\xcd";
|
|
constexpr size_t kInvalidVersionBufferLen =
|
|
sizeof(kInvalidVersionBuffer) - 1; // Remove trailing NUL.
|
|
|
|
// Buffer representing process which crashed while in the middle of a Push()
|
|
// operation, with a previously-Push()ed buffer whose length was zeroed out at
|
|
// the start.
|
|
constexpr char kMidCrashBuffer[] =
|
|
"\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x42"
|
|
"\x23";
|
|
constexpr size_t kMidCrashBufferLen =
|
|
sizeof(kMidCrashBuffer) - 1; // Remove trailing NUL.
|
|
|
|
constexpr uint8_t kHello[] = {0x68, 0x65, 0x6c, 0x6c, 0x6f};
|
|
|
|
// Invalid buffer containing malformed varint in data payload (Base 128 varint
|
|
// with length 6, which would represent a data length > 32 bits).
|
|
constexpr char kInvalidBase128VarintBuffer[] =
|
|
"\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x80\x80"
|
|
"\x80\x80\x80\x01";
|
|
constexpr size_t kInvalidBase128VarintBufferLen =
|
|
sizeof(kInvalidBase128VarintBuffer) - 1; // Remove trailing NUL.
|
|
|
|
// Invalid buffer containing malformed varint in data payload (Base 128 varint
|
|
// with length 5 but bits 33 and 34 set, which would represent a data length >
|
|
// 32 bits).
|
|
constexpr char kInvalidBase128VarintBits33And34SetBuffer[] =
|
|
"\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x80\x80"
|
|
"\x80\x80\x60";
|
|
constexpr size_t kInvalidBase128VarintBits33And34SetBufferLen =
|
|
sizeof(kInvalidBase128VarintBits33And34SetBuffer) -
|
|
1; // Remove trailing NUL.
|
|
|
|
// Invalid buffer containing too-short data payload (varint length indicates
|
|
// payload length is 4 but payload only contains 3 bytes).
|
|
constexpr char kInvalidPayloadBufferTooShort[] =
|
|
"\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04"
|
|
"\x42\x42\x42";
|
|
constexpr size_t kInvalidPayloadBufferTooShortLen =
|
|
sizeof(kInvalidPayloadBufferTooShort) - 1; // Remove trailing NUL.
|
|
|
|
TEST(LengthDelimitedRingBufferTest,
|
|
RingBufferDataShouldStartWithMagicAndVersion) {
|
|
RingBufferData ring_buffer;
|
|
const void* ring_buffer_bytes = static_cast<const void*>(&ring_buffer);
|
|
EXPECT_THAT(memcmp(ring_buffer_bytes, "\x1e\x0d\xb0\xca\x01\x00\x00\x00", 8),
|
|
Eq(0));
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest,
|
|
EmptyBufferSizeShouldIncludeHeaderInRingBufferLength) {
|
|
RingBufferData ring_buffer;
|
|
EXPECT_THAT(ring_buffer.GetRingBufferLength(),
|
|
Eq(16U)); // 4 for uint32 magic, 4 for uint32 version, 4 for
|
|
// uint32 read_pos, 4 for uint32 length
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest,
|
|
NonEmptyBufferSizeShouldIncludeHeaderAndData) {
|
|
RingBufferData ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
ASSERT_THAT(writer.Push(kHello, sizeof(kHello)), IsTrue());
|
|
EXPECT_THAT(ring_buffer.GetRingBufferLength(),
|
|
Eq(22U)); // 16 for header, 1 for varint length, 5 for data
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest, PopOnEmptyBufferShouldFail) {
|
|
RingBufferData ring_buffer;
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> result;
|
|
EXPECT_THAT(reader.Pop(result), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest, PushZeroLengthShouldFail) {
|
|
RingBufferData ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
ASSERT_THAT(writer.Push(nullptr, 0), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest, PushExactlyBufferSizeThenPopShouldSucceed) {
|
|
RingBufferData ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
ASSERT_THAT(writer.Push(kHello, sizeof(kHello)), IsTrue());
|
|
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> result;
|
|
EXPECT_THAT(reader.Pop(result), IsTrue());
|
|
const std::vector<uint8_t> expected_first = {0x68, 0x65, 0x6c, 0x6c, 0x6f};
|
|
EXPECT_THAT(result, Eq(expected_first));
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest, PushLargerThanBufferSizeShouldFail) {
|
|
RingBufferData<4> ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
EXPECT_THAT(writer.Push(kHello, sizeof(kHello)), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest,
|
|
PushUntilFullThenPopUntilEmptyShouldReturnInFIFOOrder) {
|
|
RingBufferData<4> ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
constexpr uint8_t a = 0x41;
|
|
EXPECT_THAT(writer.Push(&a, sizeof(a)),
|
|
IsTrue()); // Writes 2 bytes (1 for length)
|
|
constexpr uint8_t b = 0x42;
|
|
EXPECT_THAT(writer.Push(&b, sizeof(b)),
|
|
IsTrue()); // Writes 2 bytes (1 for length)
|
|
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> first;
|
|
EXPECT_THAT(reader.Pop(first), IsTrue());
|
|
const std::vector<uint8_t> expected_first = {0x41};
|
|
EXPECT_THAT(first, Eq(expected_first));
|
|
|
|
std::vector<uint8_t> second;
|
|
EXPECT_THAT(reader.Pop(second), IsTrue());
|
|
const std::vector<uint8_t> expected_second = {0x42};
|
|
EXPECT_THAT(second, Eq(expected_second));
|
|
|
|
std::vector<uint8_t> empty;
|
|
EXPECT_THAT(reader.Pop(empty), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferTest,
|
|
PushThenPopBuffersOfDifferingLengthsShouldReturnBuffers) {
|
|
RingBufferData<5> ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
constexpr uint8_t ab[2] = {0x41, 0x42};
|
|
EXPECT_THAT(writer.Push(ab, sizeof(ab)),
|
|
IsTrue()); // Writes 3 bytes (1 for length)
|
|
constexpr uint8_t c = 0x43;
|
|
EXPECT_THAT(writer.Push(&c, sizeof(c)),
|
|
IsTrue()); // Writes 2 bytes (1 for length)
|
|
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> first;
|
|
EXPECT_THAT(reader.Pop(first), IsTrue());
|
|
const std::vector<uint8_t> expected_first = {0x41, 0x42};
|
|
EXPECT_THAT(first, Eq(expected_first));
|
|
|
|
std::vector<uint8_t> second;
|
|
EXPECT_THAT(reader.Pop(second), IsTrue());
|
|
const std::vector<uint8_t> expected_second = {0x43};
|
|
EXPECT_THAT(second, Eq(expected_second));
|
|
|
|
std::vector<uint8_t> empty;
|
|
EXPECT_THAT(reader.Pop(empty), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest, PushOnFullBufferShouldOverwriteOldest) {
|
|
RingBufferData<4> ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
constexpr uint8_t a = 0x41;
|
|
EXPECT_THAT(writer.Push(&a, sizeof(a)),
|
|
IsTrue()); // Writes 2 bytes (1 for length)
|
|
constexpr uint8_t b = 0x42;
|
|
EXPECT_THAT(writer.Push(&b, sizeof(b)),
|
|
IsTrue()); // Writes 2 bytes (1 for length)
|
|
constexpr uint8_t c = 0x43;
|
|
EXPECT_THAT(writer.Push(&c, sizeof(c)), IsTrue()); // Should overwrite "A"
|
|
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> first;
|
|
EXPECT_THAT(reader.Pop(first), IsTrue());
|
|
const std::vector<uint8_t> expected_first = {uint8_t{0x42}};
|
|
EXPECT_THAT(first, Eq(expected_first));
|
|
|
|
std::vector<uint8_t> second;
|
|
EXPECT_THAT(reader.Pop(second), IsTrue());
|
|
const std::vector<uint8_t> expected_second = {uint8_t{0x43}};
|
|
EXPECT_THAT(second, Eq(expected_second));
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest,
|
|
PushOnFullBufferShouldOverwriteMultipleOldest) {
|
|
RingBufferData<4> ring_buffer;
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
constexpr uint8_t a = 0x41;
|
|
EXPECT_THAT(writer.Push(&a, sizeof(a)),
|
|
IsTrue()); // Writes 2 bytes (1 for length)
|
|
constexpr uint8_t b = 0x42;
|
|
EXPECT_THAT(writer.Push(&b, sizeof(b)),
|
|
IsTrue()); // Writes 2 bytes (1 for length)
|
|
constexpr uint8_t cd[] = {0x43, 0x44};
|
|
EXPECT_THAT(writer.Push(cd, sizeof(cd)),
|
|
IsTrue()); // Needs 3 bytes; should overwrite "A" and "B"
|
|
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> first;
|
|
EXPECT_THAT(reader.Pop(first), IsTrue());
|
|
const std::vector<uint8_t> expected_first = {0x43, 0x44};
|
|
EXPECT_THAT(first, Eq(expected_first));
|
|
|
|
std::vector<uint8_t> empty;
|
|
EXPECT_THAT(reader.Pop(empty), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest, PushThenPopWithLengthVarintTwoBytes) {
|
|
RingBufferData ring_buffer;
|
|
decltype(ring_buffer)::SizeType size = 150;
|
|
std::string s(size, 'X');
|
|
LengthDelimitedRingBufferWriter writer(ring_buffer);
|
|
ASSERT_THAT(writer.Push(reinterpret_cast<const uint8_t*>(s.c_str()), size),
|
|
IsTrue());
|
|
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> first;
|
|
EXPECT_THAT(reader.Pop(first), IsTrue());
|
|
std::string result(reinterpret_cast<const char*>(first.data()), first.size());
|
|
EXPECT_THAT(result, Eq(s));
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest, DeserializeFromTooShortShouldFail) {
|
|
RingBufferData<1> ring_buffer;
|
|
EXPECT_THAT(ring_buffer.DeserializeFromBuffer(nullptr, 0), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest, DeserializeFromTooLongShouldFail) {
|
|
RingBufferData<1> ring_buffer;
|
|
// This buffer is size 3; it won't fit in the template arg (size 1).
|
|
EXPECT_THAT(ring_buffer.DeserializeFromBuffer(
|
|
reinterpret_cast<const uint8_t*>(kValidBufferSize3),
|
|
kValidBufferSize3Len),
|
|
IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest,
|
|
DeserializeFromInvalidVersionShouldFail) {
|
|
RingBufferData<3> ring_buffer;
|
|
EXPECT_THAT(ring_buffer.DeserializeFromBuffer(
|
|
reinterpret_cast<const uint8_t*>(kInvalidVersionBuffer),
|
|
kInvalidVersionBufferLen),
|
|
IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest,
|
|
DeserializeFromInvalidVarintLengthShouldSucceedButPopShouldFail) {
|
|
RingBufferData ring_buffer;
|
|
EXPECT_THAT(ring_buffer.DeserializeFromBuffer(
|
|
reinterpret_cast<const uint8_t*>(kInvalidBase128VarintBuffer),
|
|
kInvalidBase128VarintBufferLen),
|
|
IsTrue());
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> data;
|
|
EXPECT_THAT(reader.Pop(data), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest,
|
|
DeserializeFromInvalidVarintBitsShouldSucceedButPopShouldFail) {
|
|
RingBufferData ring_buffer;
|
|
EXPECT_THAT(ring_buffer.DeserializeFromBuffer(
|
|
reinterpret_cast<const uint8_t*>(
|
|
kInvalidBase128VarintBits33And34SetBuffer),
|
|
kInvalidBase128VarintBits33And34SetBufferLen),
|
|
IsTrue());
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> data;
|
|
EXPECT_THAT(reader.Pop(data), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest,
|
|
DeserializeFromInvalidPayloadBufferTooShortShouldSucceedButPopShouldFail) {
|
|
RingBufferData ring_buffer;
|
|
EXPECT_THAT(
|
|
ring_buffer.DeserializeFromBuffer(
|
|
reinterpret_cast<const uint8_t*>(kInvalidPayloadBufferTooShort),
|
|
kInvalidPayloadBufferTooShortLen),
|
|
IsTrue());
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> data;
|
|
EXPECT_THAT(reader.Pop(data), IsFalse());
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest,
|
|
DeserializeFromFullBufferShouldSucceed) {
|
|
RingBufferData<3> ring_buffer;
|
|
EXPECT_THAT(ring_buffer.DeserializeFromBuffer(
|
|
reinterpret_cast<const uint8_t*>(kValidBufferSize3),
|
|
kValidBufferSize3Len),
|
|
IsTrue());
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
std::vector<uint8_t> data;
|
|
EXPECT_THAT(reader.Pop(data), IsTrue());
|
|
const std::vector<uint8_t> expected = {0x42, 0x23};
|
|
EXPECT_THAT(data, Eq(expected));
|
|
}
|
|
|
|
TEST(LengthDelimitedRingBufferDataTest,
|
|
DeserializeFromMidCrashBufferShouldSucceedButSubsequentPopShouldFail) {
|
|
RingBufferData ring_buffer;
|
|
EXPECT_THAT(ring_buffer.DeserializeFromBuffer(
|
|
reinterpret_cast<const uint8_t*>(kMidCrashBuffer),
|
|
kMidCrashBufferLen),
|
|
IsTrue());
|
|
LengthDelimitedRingBufferReader reader(ring_buffer);
|
|
// Pop should fail since the length was written to be 0.
|
|
std::vector<uint8_t> data;
|
|
EXPECT_THAT(reader.Pop(data), IsFalse());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace test
|
|
} // namespace crashpad
|