Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tools: update inspector_protocol to e8ba1a7 #39694

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions tools/inspector_protocol/code_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ def init_defaults(config_tuple, path, defaults):
".lib": False,
".lib.export_macro": "",
".lib.export_header": False,
# The encoding lib consists of encoding/encoding.h and
# encoding/encoding.cc in its subdirectory, which binaries
# may link / depend on, instead of relying on the
# JINJA2 templates lib/encoding_{h,cc}.template.
# In that case, |header| identifies the include file
# and |namespace| is the namespace it's using. Usually
# inspector_protocol_encoding but for v8's copy it's
# v8_inspector_protocol_encoding.
# TODO(johannes): Migrate away from lib/encoding_{h,cc}.template
# in favor of this.
".encoding_lib": { "header": "", "namespace": []},
}
for key_value in config_values:
parts = key_value.split("=")
Expand Down
57 changes: 27 additions & 30 deletions tools/inspector_protocol/encoding/encoding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,10 @@ namespace internals {
// |type| is the major type as specified in RFC 7049 Section 2.1.
// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
// (e.g. for BYTE_STRING).
// If successful, returns the number of bytes read. Otherwise returns -1.
// TODO(johannes): change return type to size_t and use 0 for error.
int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
// If successful, returns the number of bytes read. Otherwise returns 0.
size_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
if (bytes.empty())
return -1;
return 0;
uint8_t initial_byte = bytes[0];
*type = MajorType((initial_byte & kMajorTypeMask) >> kMajorTypeBitShift);

Expand All @@ -203,32 +202,32 @@ int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
if (additional_information == kAdditionalInformation1Byte) {
// Values 24-255 are encoded with one initial byte, followed by the value.
if (bytes.size() < 2)
return -1;
return 0;
*value = ReadBytesMostSignificantByteFirst<uint8_t>(bytes.subspan(1));
return 2;
}
if (additional_information == kAdditionalInformation2Bytes) {
// Values 256-65535: 1 initial byte + 2 bytes payload.
if (bytes.size() < 1 + sizeof(uint16_t))
return -1;
return 0;
*value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
return 3;
}
if (additional_information == kAdditionalInformation4Bytes) {
// 32 bit uint: 1 initial byte + 4 bytes payload.
if (bytes.size() < 1 + sizeof(uint32_t))
return -1;
return 0;
*value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
return 5;
}
if (additional_information == kAdditionalInformation8Bytes) {
// 64 bit uint: 1 initial byte + 8 bytes payload.
if (bytes.size() < 1 + sizeof(uint64_t))
return -1;
return 0;
*value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
return 9;
}
return -1;
return 0;
}

// Writes the start of a token with |type|. The |value| may indicate the size,
Expand Down Expand Up @@ -770,10 +769,10 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
SetToken(CBORTokenTag::NULL_VALUE, 1);
return;
case kExpectedConversionToBase64Tag: { // BINARY
const int8_t bytes_read = internals::ReadTokenStart(
const size_t bytes_read = internals::ReadTokenStart(
bytes_.subspan(status_.pos + 1), &token_start_type_,
&token_start_internal_value_);
if (bytes_read < 0 || token_start_type_ != MajorType::BYTE_STRING ||
if (!bytes_read || token_start_type_ != MajorType::BYTE_STRING ||
token_start_internal_value_ > kMaxValidLength) {
SetError(Error::CBOR_INVALID_BINARY);
return;
Expand Down Expand Up @@ -823,48 +822,47 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
return;
}
default: {
const int8_t token_start_length = internals::ReadTokenStart(
const size_t bytes_read = internals::ReadTokenStart(
bytes_.subspan(status_.pos), &token_start_type_,
&token_start_internal_value_);
const bool success = token_start_length >= 0;
switch (token_start_type_) {
case MajorType::UNSIGNED: // INT32.
// INT32 is a signed int32 (int32 makes sense for the
// inspector_protocol, it's not a CBOR limitation), so we check
// against the signed max, so that the allowable values are
// 0, 1, 2, ... 2^31 - 1.
if (!success ||
static_cast<int64_t>(std::numeric_limits<int32_t>::max()) <
static_cast<int64_t>(token_start_internal_value_)) {
if (!bytes_read || std::numeric_limits<int32_t>::max() <
token_start_internal_value_) {
SetError(Error::CBOR_INVALID_INT32);
return;
}
SetToken(CBORTokenTag::INT32, token_start_length);
SetToken(CBORTokenTag::INT32, bytes_read);
return;
case MajorType::NEGATIVE: { // INT32.
// INT32 is a signed int32 (int32 makes sense for the
// inspector_protocol, it's not a CBOR limitation); in CBOR, the
// negative values for INT32 are represented as NEGATIVE, that is, -1
// INT32 is represented as 1 << 5 | 0 (major type 1, additional info
// value 0). The minimal allowed INT32 value in our protocol is
// std::numeric_limits<int32_t>::min(). We check for it by directly
// checking the payload against the maximal allowed signed (!) int32
// value.
if (!success || token_start_internal_value_ >
std::numeric_limits<int32_t>::max()) {
// value 0).
// The represented allowed values range is -1 to -2^31.
// They are mapped into the encoded range of 0 to 2^31-1.
// We check the the payload in token_start_internal_value_ against
// that range (2^31-1 is also known as
// std::numeric_limits<int32_t>::max()).
if (!bytes_read || token_start_internal_value_ >
std::numeric_limits<int32_t>::max()) {
SetError(Error::CBOR_INVALID_INT32);
return;
}
SetToken(CBORTokenTag::INT32, token_start_length);
SetToken(CBORTokenTag::INT32, bytes_read);
return;
}
case MajorType::STRING: { // STRING8.
if (!success || token_start_internal_value_ > kMaxValidLength) {
if (!bytes_read || token_start_internal_value_ > kMaxValidLength) {
SetError(Error::CBOR_INVALID_STRING8);
return;
}
uint64_t token_byte_length =
token_start_internal_value_ + token_start_length;
uint64_t token_byte_length = token_start_internal_value_ + bytes_read;
if (token_byte_length > remaining_bytes) {
SetError(Error::CBOR_INVALID_STRING8);
return;
Expand All @@ -876,13 +874,12 @@ void CBORTokenizer::ReadNextToken(bool enter_envelope) {
case MajorType::BYTE_STRING: { // STRING16.
// Length must be divisible by 2 since UTF16 is 2 bytes per
// character, hence the &1 check.
if (!success || token_start_internal_value_ > kMaxValidLength ||
if (!bytes_read || token_start_internal_value_ > kMaxValidLength ||
token_start_internal_value_ & 1) {
SetError(Error::CBOR_INVALID_STRING16);
return;
}
uint64_t token_byte_length =
token_start_internal_value_ + token_start_length;
uint64_t token_byte_length = token_start_internal_value_ + bytes_read;
if (token_byte_length > remaining_bytes) {
SetError(Error::CBOR_INVALID_STRING16);
return;
Expand Down
2 changes: 1 addition & 1 deletion tools/inspector_protocol/encoding/encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ Status AppendString8EntryToCBORMap(span<uint8_t> string8_key,
std::string* cbor);

namespace internals { // Exposed only for writing tests.
int8_t ReadTokenStart(span<uint8_t> bytes,
size_t ReadTokenStart(span<uint8_t> bytes,
cbor::MajorType* type,
uint64_t* value);

Expand Down
8 changes: 7 additions & 1 deletion tools/inspector_protocol/encoding/encoding_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,9 @@ TEST(EncodeDecodeInt32Test, RoundtripsInt32Max) {
}

TEST(EncodeDecodeInt32Test, RoundtripsInt32Min) {
// std::numeric_limits<int32_t> is encoded as a uint32 after the initial byte.
// std::numeric_limits<int32_t> is encoded as a uint32 (4 unsigned bytes)
// after the initial byte, which effectively carries the sign by
// designating the token as NEGATIVE.
std::vector<uint8_t> encoded;
EncodeInt32(std::numeric_limits<int32_t>::min(), &encoded);
// 1 for initial byte, 4 for the uint32.
Expand All @@ -248,6 +250,10 @@ TEST(EncodeDecodeInt32Test, RoundtripsInt32Min) {
CBORTokenizer tokenizer(SpanFrom(encoded));
EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
EXPECT_EQ(std::numeric_limits<int32_t>::min(), tokenizer.GetInt32());
// It's nice to see how the min int32 value reads in hex:
// That is, -1 minus the unsigned payload (0x7fffffff, see above).
int32_t expected = -1 - 0x7fffffff;
EXPECT_EQ(expected, tokenizer.GetInt32());
tokenizer.Next();
EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
}
Expand Down
28 changes: 28 additions & 0 deletions tools/inspector_protocol/lib/Values_cpp.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

//#include "Values.h"

{% if config.encoding_lib.header %}
#include "{{config.encoding_lib.header}}"
{% endif %}

{% for namespace in config.protocol.namespace %}
namespace {{namespace}} {
{% endfor %}
Expand Down Expand Up @@ -64,6 +68,30 @@ void escapeStringForJSONInternal(const Char* str, unsigned len,
// to this constant.
static constexpr int kStackLimitValues = 1000;

{% if config.encoding_lib.namespace %}
using {{"::".join(config.encoding_lib.namespace)}}::Error;
using {{"::".join(config.encoding_lib.namespace)}}::Status;
using {{"::".join(config.encoding_lib.namespace)}}::span;
namespace cbor {
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::CBORTokenTag;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::CBORTokenizer;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeBinary;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeDouble;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeFalse;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeFromLatin1;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeFromUTF16;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeIndefiniteLengthArrayStart;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeIndefiniteLengthMapStart;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeInt32;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeNull;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeStop;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeString8;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EncodeTrue;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::EnvelopeEncoder;
using {{"::".join(config.encoding_lib.namespace + ['cbor'])}}::InitialByteForEnvelope;
} // namespace cbor
{% endif %}

// Below are three parsing routines for CBOR, which cover enough
// to roundtrip JSON messages.
std::unique_ptr<DictionaryValue> parseMap(int32_t stack_depth, cbor::CBORTokenizer* tokenizer);
Expand Down
Loading