/* * Copyright (C) 2018 The Android Open Source Project * * 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. */ #ifndef INCLUDE_PERFETTO_PROTOZERO_PROTO_DECODER_H_ #define INCLUDE_PERFETTO_PROTOZERO_PROTO_DECODER_H_ #include <stdint.h> #include <array> #include <memory> #include <vector> #include "perfetto/base/compiler.h" #include "perfetto/base/logging.h" #include "perfetto/protozero/field.h" #include "perfetto/protozero/proto_utils.h" namespace protozero { // A generic protobuf decoder. Doesn't require any knowledge about the proto // schema. It tokenizes fields, retrieves their ID and type and exposes // accessors to retrieve its values. // It does NOT recurse in nested submessages, instead it just computes their // boundaries, recursion is left to the caller. // This class is designed to be used in perf-sensitive contexts. It does not // allocate and does not perform any proto semantic checks (e.g. repeated / // required / optional). It's supposedly safe wrt out-of-bounds memory accesses // (see proto_decoder_fuzzer.cc). // This class serves also as a building block for TypedProtoDecoder, used when // the schema is known at compile time. class PERFETTO_EXPORT_COMPONENT ProtoDecoder { … }; // An iterator-like class used to iterate through repeated fields. Used by // TypedProtoDecoder. The iteration sequence is a bit counter-intuitive due to // the fact that fields_[field_id] holds the *last* value of the field, not the // first, but the remaining storage holds repeated fields in FIFO order. // Assume that we push the 10,11,12 into a repeated field with ID=1. // // Decoder memory layout: [ fields storage ] [ repeated fields storage ] // 1st iteration: 10 // 2nd iteration: 11 10 // 3rd iteration: 12 10 11 // // We start the iteration @ fields_[num_fields], which is the start of the // repeated fields storage, proceed until the end and lastly jump @ fields_[id]. template <typename T> class RepeatedFieldIterator { … }; // As RepeatedFieldIterator, but allows iterating over a packed repeated field // (which will be initially stored as a single length-delimited field). // See |GetPackedRepeatedField| for details. // // Assumes little endianness, and that the input buffers are well formed - // containing an exact multiple of encoded elements. template <proto_utils::ProtoWireType wire_type, typename CppType> class PackedRepeatedFieldIterator { … }; // This decoder loads all fields upfront, without recursing in nested messages. // It is used as a base class for typed decoders generated by the pbzero plugin. // The split between TypedProtoDecoderBase and TypedProtoDecoder<> is to have // unique definition of functions like ParseAllFields() and ExpandHeapStorage(). // The storage (either on-stack or on-heap) for this class is organized as // follows: // |-------------------------- fields_ ----------------------| // [ field 0 (invalid) ] [ fields 1 .. N ] [ repeated fields ] // ^ ^ // num_fields_ size_ // Note that if a message has high field numbers, upon creation |size_| can be // < |num_fields_| (until a heap expansion is hit while inserting). class PERFETTO_EXPORT_COMPONENT TypedProtoDecoderBase : public ProtoDecoder { … }; // This constant is a tradeoff between having a larger stack frame and being // able to decode field IDs up to N (or N - num_fields repeated fields) without // falling back on the heap. #define PROTOZERO_DECODER_INITIAL_STACK_CAPACITY … // Template class instantiated by the auto-generated decoder classes declared in // xxx.pbzero.h files. template <int MAX_FIELD_ID, bool HAS_NONPACKED_REPEATED_FIELDS> class TypedProtoDecoder : public TypedProtoDecoderBase { … }; } // namespace protozero #endif // INCLUDE_PERFETTO_PROTOZERO_PROTO_DECODER_H_