diff --git a/bazel/envoy_build_system.bzl b/bazel/envoy_build_system.bzl index 6aede4ad339fb..4e8cbd438d993 100644 --- a/bazel/envoy_build_system.bzl +++ b/bazel/envoy_build_system.bzl @@ -13,6 +13,7 @@ def envoy_copts(repository, test = False): "-Wnon-virtual-dtor", "-Woverloaded-virtual", "-Wold-style-cast", + "-Wvla", "-std=c++14", ] diff --git a/include/envoy/common/platform.h b/include/envoy/common/platform.h index dfad9b2862753..bfc8eef2e12e9 100644 --- a/include/envoy/common/platform.h +++ b/include/envoy/common/platform.h @@ -2,16 +2,11 @@ // NOLINT(namespace-envoy) #if !defined(_MSC_VER) -#define STACK_ALLOC_ARRAY(var, type, num) type var[num] - #define PACKED_STRUCT(definition, ...) definition, ##__VA_ARGS__ __attribute__((packed)) #else #include -#define STACK_ALLOC_ARRAY(var, type, num) \ - type* var = static_cast(::_alloca(sizeof(type) * num)) - #define PACKED_STRUCT(definition, ...) \ __pragma(pack(push, 1)) definition, ##__VA_ARGS__; \ __pragma(pack(pop)) diff --git a/source/common/buffer/BUILD b/source/common/buffer/BUILD index e520d65d75f46..617cce095b2d0 100644 --- a/source/common/buffer/BUILD +++ b/source/common/buffer/BUILD @@ -26,6 +26,7 @@ envoy_cc_library( "//include/envoy/buffer:buffer_interface", "//source/common/api:os_sys_calls_lib", "//source/common/common:non_copyable", + "//source/common/common:stack_array", "//source/common/event:libevent_lib", ], ) diff --git a/source/common/buffer/buffer_impl.cc b/source/common/buffer/buffer_impl.cc index 565fadca06f84..eee6e265ac531 100644 --- a/source/common/buffer/buffer_impl.cc +++ b/source/common/buffer/buffer_impl.cc @@ -3,10 +3,9 @@ #include #include -#include "envoy/common/platform.h" - #include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" +#include "common/common/stack_array.h" #include "event2/buffer.h" @@ -36,10 +35,9 @@ void OwnedImpl::add(const std::string& data) { void OwnedImpl::add(const Instance& data) { uint64_t num_slices = data.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, RawSlice, num_slices); - data.getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - RawSlice& slice = slices[i]; + STACK_ARRAY(slices, RawSlice, num_slices); + data.getRawSlices(slices.begin(), num_slices); + for (const RawSlice& slice : slices) { add(slice.mem_, slice.len_); } } @@ -116,7 +114,7 @@ Api::SysCallIntResult OwnedImpl::read(int fd, uint64_t max_length) { constexpr uint64_t MaxSlices = 2; RawSlice slices[MaxSlices]; const uint64_t num_slices = reserve(max_length, slices, MaxSlices); - STACK_ALLOC_ARRAY(iov, iovec, num_slices); + STACK_ARRAY(iov, iovec, num_slices); uint64_t num_slices_to_read = 0; uint64_t num_bytes_to_read = 0; for (; num_slices_to_read < num_slices && num_bytes_to_read < max_length; num_slices_to_read++) { @@ -130,7 +128,7 @@ Api::SysCallIntResult OwnedImpl::read(int fd, uint64_t max_length) { ASSERT(num_bytes_to_read <= max_length); auto& os_syscalls = Api::OsSysCallsSingleton::get(); const Api::SysCallSizeResult result = - os_syscalls.readv(fd, iov, static_cast(num_slices_to_read)); + os_syscalls.readv(fd, iov.begin(), static_cast(num_slices_to_read)); if (result.rc_ < 0) { return {static_cast(result.rc_), result.errno_}; } @@ -171,7 +169,7 @@ Api::SysCallIntResult OwnedImpl::write(int fd) { constexpr uint64_t MaxSlices = 16; RawSlice slices[MaxSlices]; const uint64_t num_slices = std::min(getRawSlices(slices, MaxSlices), MaxSlices); - STACK_ALLOC_ARRAY(iov, iovec, num_slices); + STACK_ARRAY(iov, iovec, num_slices); uint64_t num_slices_to_write = 0; for (uint64_t i = 0; i < num_slices; i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { @@ -184,7 +182,7 @@ Api::SysCallIntResult OwnedImpl::write(int fd) { return {0, 0}; } auto& os_syscalls = Api::OsSysCallsSingleton::get(); - const Api::SysCallSizeResult result = os_syscalls.writev(fd, iov, num_slices_to_write); + const Api::SysCallSizeResult result = os_syscalls.writev(fd, iov.begin(), num_slices_to_write); if (result.rc_ > 0) { drain(static_cast(result.rc_)); } @@ -201,17 +199,15 @@ OwnedImpl::OwnedImpl(const void* data, uint64_t size) : OwnedImpl() { add(data, std::string OwnedImpl::toString() const { uint64_t num_slices = getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, RawSlice, num_slices); - getRawSlices(slices, num_slices); + STACK_ARRAY(slices, RawSlice, num_slices); + getRawSlices(slices.begin(), num_slices); size_t len = 0; - for (uint64_t i = 0; i < num_slices; i++) { - RawSlice& slice = slices[i]; + for (const RawSlice& slice : slices) { len += slice.len_; } std::string output; output.reserve(len); - for (uint64_t i = 0; i < num_slices; i++) { - RawSlice& slice = slices[i]; + for (const RawSlice& slice : slices) { output.append(static_cast(slice.mem_), slice.len_); } diff --git a/source/common/common/BUILD b/source/common/common/BUILD index 775a770c113af..59b4eae1b3efd 100644 --- a/source/common/common/BUILD +++ b/source/common/common/BUILD @@ -33,6 +33,7 @@ envoy_cc_library( hdrs = ["base64.h"], deps = [ ":empty_string", + ":stack_array", "//include/envoy/buffer:buffer_interface", ], ) @@ -150,6 +151,14 @@ envoy_cc_library( hdrs = ["stl_helpers.h"], ) +envoy_cc_library( + name = "stack_array", + hdrs = ["stack_array.h"], + deps = [ + ":assert_lib", + ], +) + envoy_cc_library( name = "thread_annotations", hdrs = ["thread_annotations.h"], diff --git a/source/common/common/base64.cc b/source/common/common/base64.cc index f4a25183fa99f..df5c84dd222d9 100644 --- a/source/common/common/base64.cc +++ b/source/common/common/base64.cc @@ -3,9 +3,8 @@ #include #include -#include "envoy/common/platform.h" - #include "common/common/empty_string.h" +#include "common/common/stack_array.h" namespace Envoy { namespace { @@ -180,13 +179,12 @@ std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { ret.reserve(output_length); uint64_t num_slices = buffer.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - buffer.getRawSlices(slices, num_slices); + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + buffer.getRawSlices(slices.begin(), num_slices); uint64_t j = 0; uint8_t next_c = 0; - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + for (const Buffer::RawSlice& slice : slices) { const uint8_t* slice_mem = static_cast(slice.mem_); for (uint64_t i = 0; i < slice.len_ && j < length; ++i, ++j) { diff --git a/source/common/common/stack_array.h b/source/common/common/stack_array.h new file mode 100644 index 0000000000000..a7e93f01a3d34 --- /dev/null +++ b/source/common/common/stack_array.h @@ -0,0 +1,56 @@ +#pragma once + +#if !defined(WIN32) +#include + +#else +#include +#endif + +#include + +#include "common/common/assert.h" + +namespace Envoy { + +// This macro is intended to be used as a replacement for variable-length arrays. +// Note that the StackArray wrapper object will be destructed and each element's +// destructor will be called when it leaves scope. However, the memory containing +// the array won't be deallocated until the function containing the macro returns. +// We can't call alloca in the StackArray constructor since the memory would +// be freed when the constructor returns. +#define STACK_ARRAY(var, type, num) StackArray var(::alloca(sizeof(type) * num), num) + +template class StackArray { +public: + StackArray(void* buf, size_t num_items) { + ASSERT(buf != nullptr, "StackArray received null pointer"); + begin_ = static_cast(buf); + end_ = static_cast(buf) + num_items; + for (T& ref : *this) { + new (&ref) T; + } + } + + ~StackArray() { + for (T& ref : *this) { + ref.~T(); + } + } + + T* begin() { return begin_; } + + T* end() { return end_; } + + T& operator[](size_t idx) { return begin_[idx]; } + + void* operator new(size_t) = delete; + + void* operator new[](size_t) = delete; + +private: + T* begin_; + T* end_; +}; + +} // namespace Envoy diff --git a/source/common/compressor/BUILD b/source/common/compressor/BUILD index 8e37a01a23fb8..81a7e95f61c4a 100644 --- a/source/common/compressor/BUILD +++ b/source/common/compressor/BUILD @@ -17,5 +17,6 @@ envoy_cc_library( "//include/envoy/compressor:compressor_interface", "//source/common/buffer:buffer_lib", "//source/common/common:assert_lib", + "//source/common/common:stack_array", ], ) diff --git a/source/common/compressor/zlib_compressor_impl.cc b/source/common/compressor/zlib_compressor_impl.cc index b4e3fde0591dc..f02333ed40f3d 100644 --- a/source/common/compressor/zlib_compressor_impl.cc +++ b/source/common/compressor/zlib_compressor_impl.cc @@ -1,9 +1,9 @@ #include "common/compressor/zlib_compressor_impl.h" #include "envoy/common/exception.h" -#include "envoy/common/platform.h" #include "common/common/assert.h" +#include "common/common/stack_array.h" namespace Envoy { namespace Compressor { @@ -36,11 +36,10 @@ uint64_t ZlibCompressorImpl::checksum() { return zstream_ptr_->adler; } void ZlibCompressorImpl::compress(Buffer::Instance& buffer, State state) { const uint64_t num_slices = buffer.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - buffer.getRawSlices(slices, num_slices); + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + buffer.getRawSlices(slices.begin(), num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - const Buffer::RawSlice& input_slice = slices[i]; + for (const Buffer::RawSlice& input_slice : slices) { zstream_ptr_->avail_in = input_slice.len_; zstream_ptr_->next_in = static_cast(input_slice.mem_); // Z_NO_FLUSH tells the compressor to take the data in and compresses it as much as possible diff --git a/source/common/decompressor/zlib_decompressor_impl.cc b/source/common/decompressor/zlib_decompressor_impl.cc index ad341a56ac5bd..27967811a3549 100644 --- a/source/common/decompressor/zlib_decompressor_impl.cc +++ b/source/common/decompressor/zlib_decompressor_impl.cc @@ -1,9 +1,9 @@ #include "common/decompressor/zlib_decompressor_impl.h" #include "envoy/common/exception.h" -#include "envoy/common/platform.h" #include "common/common/assert.h" +#include "common/common/stack_array.h" namespace Envoy { namespace Decompressor { @@ -35,11 +35,10 @@ uint64_t ZlibDecompressorImpl::checksum() { return zstream_ptr_->adler; } void ZlibDecompressorImpl::decompress(const Buffer::Instance& input_buffer, Buffer::Instance& output_buffer) { const uint64_t num_slices = input_buffer.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - input_buffer.getRawSlices(slices, num_slices); + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + input_buffer.getRawSlices(slices.begin(), num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& input_slice = slices[i]; + for (const Buffer::RawSlice& input_slice : slices) { zstream_ptr_->avail_in = input_slice.len_; zstream_ptr_->next_in = static_cast(input_slice.mem_); while (inflateNext()) { diff --git a/source/common/filesystem/filesystem_impl.cc b/source/common/filesystem/filesystem_impl.cc index 2c6f9865dc5fb..e85607199d960 100644 --- a/source/common/filesystem/filesystem_impl.cc +++ b/source/common/filesystem/filesystem_impl.cc @@ -11,7 +11,6 @@ #include #include "envoy/common/exception.h" -#include "envoy/common/platform.h" #include "envoy/common/time.h" #include "envoy/event/dispatcher.h" @@ -19,6 +18,7 @@ #include "common/common/assert.h" #include "common/common/fmt.h" #include "common/common/lock_guard.h" +#include "common/common/stack_array.h" #include "common/common/thread.h" #include "absl/strings/match.h" @@ -142,8 +142,8 @@ FileImpl::~FileImpl() { void FileImpl::doWrite(Buffer::Instance& buffer) { uint64_t num_slices = buffer.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - buffer.getRawSlices(slices, num_slices); + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + buffer.getRawSlices(slices.begin(), num_slices); // We must do the actual writes to disk under lock, so that we don't intermix chunks from // different FileImpl pointing to the same underlying file. This can happen either via hot @@ -155,8 +155,7 @@ void FileImpl::doWrite(Buffer::Instance& buffer) { // process lock or had multiple locks. { Thread::LockGuard lock(file_lock_); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + for (const Buffer::RawSlice& slice : slices) { const Api::SysCallSizeResult result = os_sys_calls_.write(fd_, slice.mem_, slice.len_); ASSERT(result.rc_ == static_cast(slice.len_)); stats_.write_completed_.inc(); diff --git a/source/common/grpc/BUILD b/source/common/grpc/BUILD index 3507c69d1e490..f4fd5d046a049 100644 --- a/source/common/grpc/BUILD +++ b/source/common/grpc/BUILD @@ -43,6 +43,7 @@ envoy_cc_library( "//include/envoy/buffer:buffer_interface", "//source/common/buffer:buffer_lib", "//source/common/common:minimal_logger_lib", + "//source/common/common:stack_array", ], ) diff --git a/source/common/grpc/codec.cc b/source/common/grpc/codec.cc index aa07066fe0b89..77e778a9df375 100644 --- a/source/common/grpc/codec.cc +++ b/source/common/grpc/codec.cc @@ -4,9 +4,8 @@ #include #include -#include "envoy/common/platform.h" - #include "common/buffer/buffer_impl.h" +#include "common/common/stack_array.h" namespace Envoy { namespace Grpc { @@ -25,10 +24,9 @@ Decoder::Decoder() : state_(State::FH_FLAG) {} bool Decoder::decode(Buffer::Instance& input, std::vector& output) { uint64_t count = input.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, count); - input.getRawSlices(slices, count); - for (uint64_t i = 0; i < count; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, count); + input.getRawSlices(slices.begin(), count); + for (const Buffer::RawSlice& slice : slices) { uint8_t* mem = reinterpret_cast(slice.mem_); for (uint64_t j = 0; j < slice.len_;) { uint8_t c = *mem; diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 1b12c863278c2..d09661537190c 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -203,6 +203,7 @@ envoy_cc_library( "//include/envoy/http:message_interface", "//source/common/buffer:buffer_lib", "//source/common/common:non_copyable", + "//source/common/common:stack_array", ], ) diff --git a/source/common/http/http1/codec_impl.cc b/source/common/http/http1/codec_impl.cc index 4fa2832a97e91..d81bd2d0e910d 100644 --- a/source/common/http/http1/codec_impl.cc +++ b/source/common/http/http1/codec_impl.cc @@ -4,12 +4,12 @@ #include #include "envoy/buffer/buffer.h" -#include "envoy/common/platform.h" #include "envoy/http/header_map.h" #include "envoy/network/connection.h" #include "common/common/enum_to_int.h" #include "common/common/fmt.h" +#include "common/common/stack_array.h" #include "common/common/utility.h" #include "common/http/exception.h" #include "common/http/headers.h" @@ -332,10 +332,9 @@ bool ConnectionImpl::maybeDirectDispatch(Buffer::Instance& data) { ssize_t total_parsed = 0; uint64_t num_slices = data.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - data.getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + data.getRawSlices(slices.begin(), num_slices); + for (const Buffer::RawSlice& slice : slices) { total_parsed += slice.len_; onBody(static_cast(slice.mem_), slice.len_); } @@ -357,10 +356,9 @@ void ConnectionImpl::dispatch(Buffer::Instance& data) { ssize_t total_parsed = 0; if (data.length() > 0) { uint64_t num_slices = data.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - data.getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + data.getRawSlices(slices.begin(), num_slices); + for (const Buffer::RawSlice& slice : slices) { total_parsed += dispatchSlice(static_cast(slice.mem_), slice.len_); } } else { diff --git a/source/common/http/http2/BUILD b/source/common/http/http2/BUILD index 4f5f5cde45784..ca7634f59e1a3 100644 --- a/source/common/http/http2/BUILD +++ b/source/common/http/http2/BUILD @@ -70,6 +70,7 @@ envoy_cc_library( "//source/common/buffer:buffer_lib", "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", + "//source/common/common:stack_array", ], ) @@ -85,6 +86,7 @@ envoy_cc_library( "//source/common/buffer:buffer_lib", "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", + "//source/common/common:stack_array", ], ) diff --git a/source/common/http/http2/codec_impl.cc b/source/common/http/http2/codec_impl.cc index 7d5b95a903c57..27ae145d0a835 100644 --- a/source/common/http/http2/codec_impl.cc +++ b/source/common/http/http2/codec_impl.cc @@ -4,7 +4,6 @@ #include #include -#include "envoy/common/platform.h" #include "envoy/event/dispatcher.h" #include "envoy/http/codes.h" #include "envoy/http/header_map.h" @@ -14,6 +13,7 @@ #include "common/common/assert.h" #include "common/common/enum_to_int.h" #include "common/common/fmt.h" +#include "common/common/stack_array.h" #include "common/common/utility.h" #include "common/http/codes.h" #include "common/http/exception.h" @@ -291,10 +291,9 @@ ConnectionImpl::~ConnectionImpl() { nghttp2_session_del(session_); } void ConnectionImpl::dispatch(Buffer::Instance& data) { ENVOY_CONN_LOG(trace, "dispatching {} bytes", connection_, data.length()); uint64_t num_slices = data.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - data.getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + data.getRawSlices(slices.begin(), num_slices); + for (const Buffer::RawSlice& slice : slices) { dispatching_ = true; ssize_t rc = nghttp2_session_mem_recv(session_, static_cast(slice.mem_), slice.len_); diff --git a/source/common/http/http2/metadata_decoder.cc b/source/common/http/http2/metadata_decoder.cc index 8c2b72739c40b..2fd440263611a 100644 --- a/source/common/http/http2/metadata_decoder.cc +++ b/source/common/http/http2/metadata_decoder.cc @@ -1,6 +1,7 @@ #include "common/http/http2/metadata_decoder.h" #include "common/common/assert.h" +#include "common/common/stack_array.h" namespace Envoy { namespace Http { @@ -39,8 +40,8 @@ bool MetadataDecoder::onMetadataFrameComplete(bool end_metadata) { bool MetadataDecoder::decodeMetadataPayloadUsingNghttp2(bool end_metadata) { // Computes how many slices are needed to get all the data out. const int num_slices = payload_.getRawSlices(nullptr, 0); - Buffer::RawSlice slices[num_slices]; - payload_.getRawSlices(slices, num_slices); + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + payload_.getRawSlices(slices.begin(), num_slices); // Data consumed by nghttp2 so far. ssize_t payload_size_consumed = 0; diff --git a/source/common/http/http2/metadata_encoder.cc b/source/common/http/http2/metadata_encoder.cc index 6f9378747c7d9..31edcdb94a221 100644 --- a/source/common/http/http2/metadata_encoder.cc +++ b/source/common/http/http2/metadata_encoder.cc @@ -1,6 +1,7 @@ #include "common/http/http2/metadata_encoder.h" #include "common/common/assert.h" +#include "common/common/stack_array.h" #include "nghttp2/nghttp2.h" @@ -35,7 +36,7 @@ bool MetadataEncoder::createHeaderBlockUsingNghttp2(MetadataMap& metadata_map) { // Constructs input for nghttp2 deflater (encoder). Encoding method used is // "HPACK Literal Header Field Never Indexed". const size_t nvlen = metadata_map.size(); - nghttp2_nv nva[nvlen]; + STACK_ARRAY(nva, nghttp2_nv, nvlen); size_t i = 0; for (const auto& header : metadata_map) { nva[i++] = {const_cast(reinterpret_cast(header.first.data())), @@ -44,7 +45,7 @@ bool MetadataEncoder::createHeaderBlockUsingNghttp2(MetadataMap& metadata_map) { } // Estimates the upper bound of output payload. - size_t buflen = nghttp2_hd_deflate_bound(deflater_.get(), nva, nvlen); + size_t buflen = nghttp2_hd_deflate_bound(deflater_.get(), nva.begin(), nvlen); if (buflen > max_payload_size_bound_) { ENVOY_LOG(error, "Payload size {} exceeds the max bound.", buflen); return false; @@ -55,7 +56,7 @@ bool MetadataEncoder::createHeaderBlockUsingNghttp2(MetadataMap& metadata_map) { // Creates payload using nghttp2. uint8_t* buf = reinterpret_cast(iovec.mem_); - ssize_t result = nghttp2_hd_deflate_hd(deflater_.get(), buf, buflen, nva, nvlen); + ssize_t result = nghttp2_hd_deflate_hd(deflater_.get(), buf, buflen, nva.begin(), nvlen); ASSERT(result > 0); iovec.len_ = result; diff --git a/source/common/http/message_impl.cc b/source/common/http/message_impl.cc index 3a252f220d0fb..a89574eec7223 100644 --- a/source/common/http/message_impl.cc +++ b/source/common/http/message_impl.cc @@ -3,7 +3,7 @@ #include #include -#include "envoy/common/platform.h" +#include "common/common/stack_array.h" namespace Envoy { namespace Http { @@ -12,10 +12,9 @@ std::string MessageImpl::bodyAsString() const { std::string ret; if (body_) { uint64_t num_slices = body_->getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - body_->getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + body_->getRawSlices(slices.begin(), num_slices); + for (const Buffer::RawSlice& slice : slices) { ret.append(reinterpret_cast(slice.mem_), slice.len_); } } diff --git a/source/common/upstream/BUILD b/source/common/upstream/BUILD index 0bd778b5b5de0..939dd70e8c7fd 100644 --- a/source/common/upstream/BUILD +++ b/source/common/upstream/BUILD @@ -143,6 +143,7 @@ envoy_cc_library( "//include/envoy/upstream:load_balancer_interface", "//include/envoy/upstream:upstream_interface", "//source/common/common:assert_lib", + "//source/common/common:stack_array", "//source/common/protobuf:utility_lib", ], ) diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index bd6a7ccde5e55..937f23a9d9794 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -4,11 +4,11 @@ #include #include -#include "envoy/common/platform.h" #include "envoy/runtime/runtime.h" #include "envoy/upstream/upstream.h" #include "common/common/assert.h" +#include "common/common/stack_array.h" #include "common/protobuf/utility.h" namespace Envoy { @@ -244,10 +244,10 @@ void ZoneAwareLoadBalancerBase::regenerateLocalityRoutingStructures() { // // Basically, fariness across localities within a priority is guaranteed. Fairness across // localities across priorities is not. - STACK_ALLOC_ARRAY(local_percentage, uint64_t, num_localities); - calculateLocalityPercentage(localHostSet().healthyHostsPerLocality(), local_percentage); - STACK_ALLOC_ARRAY(upstream_percentage, uint64_t, num_localities); - calculateLocalityPercentage(host_set.healthyHostsPerLocality(), upstream_percentage); + STACK_ARRAY(local_percentage, uint64_t, num_localities); + calculateLocalityPercentage(localHostSet().healthyHostsPerLocality(), local_percentage.begin()); + STACK_ARRAY(upstream_percentage, uint64_t, num_localities); + calculateLocalityPercentage(host_set.healthyHostsPerLocality(), upstream_percentage.begin()); // If we have lower percent of hosts in the local cluster in the same locality, // we can push all of the requests directly to upstream cluster in the same locality. diff --git a/source/extensions/filters/http/dynamo/dynamo_filter.cc b/source/extensions/filters/http/dynamo/dynamo_filter.cc index 1e3e3f134f6f7..c16a443869de7 100644 --- a/source/extensions/filters/http/dynamo/dynamo_filter.cc +++ b/source/extensions/filters/http/dynamo/dynamo_filter.cc @@ -5,11 +5,10 @@ #include #include -#include "envoy/common/platform.h" - #include "common/buffer/buffer_impl.h" #include "common/common/assert.h" #include "common/common/fmt.h" +#include "common/common/stack_array.h" #include "common/http/codes.h" #include "common/http/exception.h" #include "common/http/utility.h" @@ -138,19 +137,17 @@ std::string DynamoFilter::buildBody(const Buffer::Instance* buffered, std::string body; if (buffered) { uint64_t num_slices = buffered->getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - buffered->getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + buffered->getRawSlices(slices.begin(), num_slices); + for (const Buffer::RawSlice& slice : slices) { body.append(static_cast(slice.mem_), slice.len_); } } uint64_t num_slices = last.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - last.getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + last.getRawSlices(slices.begin(), num_slices); + for (const Buffer::RawSlice& slice : slices) { body.append(static_cast(slice.mem_), slice.len_); } diff --git a/source/extensions/filters/http/squash/squash_filter.cc b/source/extensions/filters/http/squash/squash_filter.cc index aba72e7493b3b..7019ae1b6718e 100644 --- a/source/extensions/filters/http/squash/squash_filter.cc +++ b/source/extensions/filters/http/squash/squash_filter.cc @@ -1,11 +1,11 @@ #include "extensions/filters/http/squash/squash_filter.h" -#include "envoy/common/platform.h" #include "envoy/http/codes.h" #include "common/common/empty_string.h" #include "common/common/enum_to_int.h" #include "common/common/logger.h" +#include "common/common/stack_array.h" #include "common/http/headers.h" #include "common/http/message_impl.h" #include "common/http/utility.h" @@ -304,11 +304,10 @@ void SquashFilter::cleanup() { Json::ObjectSharedPtr SquashFilter::getJsonBody(Http::MessagePtr&& m) { Buffer::InstancePtr& data = m->body(); uint64_t num_slices = data->getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - data->getRawSlices(slices, num_slices); + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + data->getRawSlices(slices.begin(), num_slices); std::string jsonbody; - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + for (const Buffer::RawSlice& slice : slices) { jsonbody += std::string(static_cast(slice.mem_), slice.len_); } diff --git a/source/extensions/filters/network/redis_proxy/BUILD b/source/extensions/filters/network/redis_proxy/BUILD index fac0c3feda790..fc9b9376739b6 100644 --- a/source/extensions/filters/network/redis_proxy/BUILD +++ b/source/extensions/filters/network/redis_proxy/BUILD @@ -41,6 +41,7 @@ envoy_cc_library( ":codec_interface", "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", + "//source/common/common:stack_array", "//source/common/common:utility_lib", ], ) diff --git a/source/extensions/filters/network/redis_proxy/codec_impl.cc b/source/extensions/filters/network/redis_proxy/codec_impl.cc index 20649b4927ba1..939f99386c342 100644 --- a/source/extensions/filters/network/redis_proxy/codec_impl.cc +++ b/source/extensions/filters/network/redis_proxy/codec_impl.cc @@ -6,6 +6,7 @@ #include "common/common/assert.h" #include "common/common/fmt.h" +#include "common/common/stack_array.h" #include "common/common/utility.h" namespace Envoy { @@ -115,8 +116,8 @@ void RespValue::type(RespType type) { void DecoderImpl::decode(Buffer::Instance& data) { uint64_t num_slices = data.getRawSlices(nullptr, 0); - Buffer::RawSlice slices[num_slices]; - data.getRawSlices(slices, num_slices); + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + data.getRawSlices(slices.begin(), num_slices); for (const Buffer::RawSlice& slice : slices) { parseSlice(slice); } diff --git a/test/common/common/BUILD b/test/common/common/BUILD index afbc825fb12f6..d0d8a9112aee5 100644 --- a/test/common/common/BUILD +++ b/test/common/common/BUILD @@ -135,6 +135,14 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "stack_array_test", + srcs = ["stack_array_test.cc"], + deps = [ + "//source/common/common:stack_array", + ], +) + envoy_cc_test( name = "to_lower_table_test", srcs = ["to_lower_table_test.cc"], diff --git a/test/common/common/stack_array_test.cc b/test/common/common/stack_array_test.cc new file mode 100644 index 0000000000000..fa857f77b05f5 --- /dev/null +++ b/test/common/common/stack_array_test.cc @@ -0,0 +1,38 @@ +#include "common/common/stack_array.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { + +class TestEntry { +public: + TestEntry() { self_ = this; } + ~TestEntry() { destructor_(val_); } + + int val_ = 0; + TestEntry* self_; + MOCK_METHOD1(destructor_, void(int)); +}; + +TEST(StackArray, ConstructorsAndDestructorsCalled) { + STACK_ARRAY(entries, TestEntry, 10); + + for (TestEntry& entry : entries) { + ASSERT_EQ(&entry, entry.self_); + EXPECT_CALL(entry, destructor_(0)).Times(1); + } +} + +TEST(StackArray, Modification) { + STACK_ARRAY(entries, TestEntry, 10); + + int i = 0; + for (TestEntry& entry : entries) { + entry.val_ = i; + EXPECT_CALL(entries[i], destructor_(i)).Times(1); + i++; + } +} + +} // namespace Envoy diff --git a/test/common/compressor/zlib_compressor_impl_test.cc b/test/common/compressor/zlib_compressor_impl_test.cc index 288fa966993ef..2167b19d27c63 100644 --- a/test/common/compressor/zlib_compressor_impl_test.cc +++ b/test/common/compressor/zlib_compressor_impl_test.cc @@ -1,7 +1,6 @@ -#include "envoy/common/platform.h" - #include "common/buffer/buffer_impl.h" #include "common/common/hex.h" +#include "common/common/stack_array.h" #include "common/compressor/zlib_compressor_impl.h" #include "test/test_common/utility.h" @@ -16,8 +15,8 @@ class ZlibCompressorImplTest : public testing::Test { protected: void expectValidFlushedBuffer(const Buffer::OwnedImpl& output_buffer) { uint64_t num_comp_slices = output_buffer.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(compressed_slices, Buffer::RawSlice, num_comp_slices); - output_buffer.getRawSlices(compressed_slices, num_comp_slices); + STACK_ARRAY(compressed_slices, Buffer::RawSlice, num_comp_slices); + output_buffer.getRawSlices(compressed_slices.begin(), num_comp_slices); const std::string header_hex_str = Hex::encode( reinterpret_cast(compressed_slices[0].mem_), compressed_slices[0].len_); @@ -37,8 +36,8 @@ class ZlibCompressorImplTest : public testing::Test { void expectValidFinishedBuffer(const Buffer::OwnedImpl& output_buffer, const uint32_t input_size) { uint64_t num_comp_slices = output_buffer.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(compressed_slices, Buffer::RawSlice, num_comp_slices); - output_buffer.getRawSlices(compressed_slices, num_comp_slices); + STACK_ARRAY(compressed_slices, Buffer::RawSlice, num_comp_slices); + output_buffer.getRawSlices(compressed_slices.begin(), num_comp_slices); const std::string header_hex_str = Hex::encode( reinterpret_cast(compressed_slices[0].mem_), compressed_slices[0].len_); diff --git a/test/common/network/dns_impl_test.cc b/test/common/network/dns_impl_test.cc index fc449bec397d0..ce6a63941f144 100644 --- a/test/common/network/dns_impl_test.cc +++ b/test/common/network/dns_impl_test.cc @@ -8,12 +8,12 @@ #include #include -#include "envoy/common/platform.h" #include "envoy/event/dispatcher.h" #include "envoy/network/address.h" #include "envoy/network/dns.h" #include "common/buffer/buffer_impl.h" +#include "common/common/stack_array.h" #include "common/common/utility.h" #include "common/event/dispatcher_impl.h" #include "common/network/address_impl.h" @@ -168,7 +168,8 @@ class TestDnsServerQuery { // The response begins with the initial part of the request // (including the question section). const size_t response_base_len = HFIXEDSZ + name_len + QFIXEDSZ; - STACK_ALLOC_ARRAY(response_base, unsigned char, response_base_len); + STACK_ARRAY(response_buf, unsigned char, response_base_len); + unsigned char* response_base = response_buf.begin(); memcpy(response_base, request, response_base_len); DNS_HEADER_SET_QR(response_base, 1); DNS_HEADER_SET_AA(response_base, 0); diff --git a/test/integration/integration.cc b/test/integration/integration.cc index a473941d0dd6f..fabb8533b2070 100644 --- a/test/integration/integration.cc +++ b/test/integration/integration.cc @@ -9,13 +9,13 @@ #include #include "envoy/buffer/buffer.h" -#include "envoy/common/platform.h" #include "envoy/http/header_map.h" #include "common/api/api_impl.h" #include "common/buffer/buffer_impl.h" #include "common/common/assert.h" #include "common/common/fmt.h" +#include "common/common/stack_array.h" #include "common/event/dispatcher_impl.h" #include "common/event/libevent.h" #include "common/network/connection_impl.h" @@ -92,10 +92,9 @@ void IntegrationStreamDecoder::decodeHeaders(Http::HeaderMapPtr&& headers, bool void IntegrationStreamDecoder::decodeData(Buffer::Instance& data, bool end_stream) { saw_end_stream_ = end_stream; uint64_t num_slices = data.getRawSlices(nullptr, 0); - STACK_ALLOC_ARRAY(slices, Buffer::RawSlice, num_slices); - data.getRawSlices(slices, num_slices); - for (uint64_t i = 0; i < num_slices; i++) { - Buffer::RawSlice& slice = slices[i]; + STACK_ARRAY(slices, Buffer::RawSlice, num_slices); + data.getRawSlices(slices.begin(), num_slices); + for (const Buffer::RawSlice& slice : slices) { body_.append(static_cast(slice.mem_), slice.len_); } diff --git a/test/test_common/utility.cc b/test/test_common/utility.cc index bd36c3e7539a1..002d315ac0232 100644 --- a/test/test_common/utility.cc +++ b/test/test_common/utility.cc @@ -23,12 +23,12 @@ #include #include "envoy/buffer/buffer.h" -#include "envoy/common/platform.h" #include "envoy/http/codec.h" #include "common/common/empty_string.h" #include "common/common/fmt.h" #include "common/common/lock_guard.h" +#include "common/common/stack_array.h" #include "common/common/utility.h" #include "common/config/bootstrap_json.h" #include "common/json/json_loader.h" @@ -101,10 +101,10 @@ bool TestUtility::buffersEqual(const Buffer::Instance& lhs, const Buffer::Instan return false; } - STACK_ALLOC_ARRAY(lhs_slices, Buffer::RawSlice, lhs_num_slices); - lhs.getRawSlices(lhs_slices, lhs_num_slices); - STACK_ALLOC_ARRAY(rhs_slices, Buffer::RawSlice, rhs_num_slices); - rhs.getRawSlices(rhs_slices, rhs_num_slices); + STACK_ARRAY(lhs_slices, Buffer::RawSlice, lhs_num_slices); + lhs.getRawSlices(lhs_slices.begin(), lhs_num_slices); + STACK_ARRAY(rhs_slices, Buffer::RawSlice, rhs_num_slices); + rhs.getRawSlices(rhs_slices.begin(), rhs_num_slices); for (size_t i = 0; i < lhs_num_slices; i++) { if (lhs_slices[i].len_ != rhs_slices[i].len_) { return false;