From f82245555e31148c739a3c6fc1a51174f18173d4 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 15 Mar 2022 12:12:22 -0700 Subject: [PATCH] Introduce ChannelArgs C++ type (#28860) * progress * basics * Automated change: Fix sanity tests * fix * fix * backout protochange * consistency in naming * Make things load bearing, fix bugs * Automated change: Fix sanity tests Co-authored-by: ctiller --- BUILD | 9 + CMakeLists.txt | 65 ++++--- build_autogenerated.yaml | 26 ++- gRPC-C++.podspec | 4 + gRPC-Core.podspec | 4 + grpc.gemspec | 2 + package.xml | 2 + src/core/lib/avl/avl.h | 73 +++++++- src/core/lib/channel/channel_args.cc | 153 +++++++++++----- src/core/lib/channel/channel_args.h | 172 +++++++++++++++++- .../channel/channel_args_preconditioning.cc | 12 +- .../channel/channel_args_preconditioning.h | 3 +- src/core/lib/resource_quota/api.cc | 35 +--- src/core/lib/resource_quota/resource_quota.h | 6 + test/core/avl/avl_fuzzer.cc | 76 +++++--- test/core/avl/avl_fuzzer.proto | 11 ++ ...h-060a9a897130ba7bb2f4313daa604c47f7c7c907 | 9 + ...h-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360 | 5 + test/core/channel/BUILD | 1 + test/core/channel/channel_args_test.cc | 154 ++++++++++------ tools/doxygen/Doxyfile.c++.internal | 2 + tools/doxygen/Doxyfile.core.internal | 2 + tools/run_tests/generated/tests.json | 48 ++--- 23 files changed, 634 insertions(+), 240 deletions(-) create mode 100644 test/core/avl/avl_fuzzer_corpus/crash-060a9a897130ba7bb2f4313daa604c47f7c7c907 create mode 100644 test/core/avl/avl_fuzzer_corpus/crash-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360 diff --git a/BUILD b/BUILD index e516293ec56..3b7a6807ee8 100644 --- a/BUILD +++ b/BUILD @@ -1769,6 +1769,9 @@ grpc_cc_library( hdrs = [ "src/core/lib/avl/avl.h", ], + external_deps = [ + "absl/container:inlined_vector", + ], deps = [ "gpr_platform", ], @@ -2390,12 +2393,18 @@ grpc_cc_library( external_deps = [ "absl/strings", "absl/strings:str_format", + "absl/types:variant", + "absl/types:optional", ], language = "c++", deps = [ + "avl", "channel_stack_type", "gpr_base", "grpc_codegen", + "match", + "ref_counted", + "ref_counted_ptr", "useful", ], ) diff --git a/CMakeLists.txt b/CMakeLists.txt index df523546dab..a7e3b1b803e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -631,7 +631,6 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_c bin_decoder_test) add_dependencies(buildtests_c bin_encoder_test) add_dependencies(buildtests_c buffer_list_test) - add_dependencies(buildtests_c channel_args_test) add_dependencies(buildtests_c channel_stack_test) add_dependencies(buildtests_c check_gcp_environment_linux_test) add_dependencies(buildtests_c check_gcp_environment_windows_test) @@ -806,6 +805,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx certificate_provider_registry_test) add_dependencies(buildtests_cxx certificate_provider_store_test) add_dependencies(buildtests_cxx cfstream_test) + add_dependencies(buildtests_cxx channel_args_test) add_dependencies(buildtests_cxx channel_arguments_test) add_dependencies(buildtests_cxx channel_creds_registry_test) add_dependencies(buildtests_cxx channel_filter_test) @@ -4676,33 +4676,6 @@ target_link_libraries(buffer_list_test ) -endif() -if(gRPC_BUILD_TESTS) - -add_executable(channel_args_test - test/core/channel/channel_args_test.cc -) - -target_include_directories(channel_args_test - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} - ${_gRPC_RE2_INCLUDE_DIR} - ${_gRPC_SSL_INCLUDE_DIR} - ${_gRPC_UPB_GENERATED_DIR} - ${_gRPC_UPB_GRPC_GENERATED_DIR} - ${_gRPC_UPB_INCLUDE_DIR} - ${_gRPC_XXHASH_INCLUDE_DIR} - ${_gRPC_ZLIB_INCLUDE_DIR} -) - -target_link_libraries(channel_args_test - ${_gRPC_ALLTARGETS_LIBRARIES} - grpc_test_util -) - - endif() if(gRPC_BUILD_TESTS) @@ -7722,6 +7695,7 @@ target_include_directories(avl_test target_link_libraries(avl_test ${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES} + absl::inlined_vector ) @@ -8485,6 +8459,41 @@ target_link_libraries(cfstream_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(channel_args_test + test/core/channel/channel_args_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + +target_include_directories(channel_args_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(channel_args_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util +) + + endif() if(gRPC_BUILD_TESTS) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index a13025d0bf6..62afec170fc 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -726,7 +726,9 @@ libs: - src/core/lib/gprpp/chunked_vector.h - src/core/lib/gprpp/cpp_impl_of.h - src/core/lib/gprpp/dual_ref_counted.h + - src/core/lib/gprpp/match.h - src/core/lib/gprpp/orphanable.h + - src/core/lib/gprpp/overload.h - src/core/lib/gprpp/ref_counted.h - src/core/lib/gprpp/ref_counted_ptr.h - src/core/lib/gprpp/table.h @@ -1901,7 +1903,9 @@ libs: - src/core/lib/gprpp/chunked_vector.h - src/core/lib/gprpp/cpp_impl_of.h - src/core/lib/gprpp/dual_ref_counted.h + - src/core/lib/gprpp/match.h - src/core/lib/gprpp/orphanable.h + - src/core/lib/gprpp/overload.h - src/core/lib/gprpp/ref_counted.h - src/core/lib/gprpp/ref_counted_ptr.h - src/core/lib/gprpp/table.h @@ -3322,15 +3326,6 @@ targets: - test/core/iomgr/buffer_list_test.cc deps: - grpc_test_util -- name: channel_args_test - build: test - language: c - headers: [] - src: - - test/core/channel/channel_args_test.cc - deps: - - grpc_test_util - uses_polling: false - name: channel_stack_test build: test language: c @@ -4538,7 +4533,8 @@ targets: - src/core/lib/avl/avl.h src: - test/core/avl/avl_test.cc - deps: [] + deps: + - absl/container:inlined_vector uses_polling: false - name: aws_request_signer_test gtest: true @@ -4854,6 +4850,16 @@ targets: - test/cpp/end2end/test_service_impl.cc deps: - grpc++_test_util +- name: channel_args_test + gtest: true + build: test + language: c++ + headers: [] + src: + - test/core/channel/channel_args_test.cc + deps: + - grpc_test_util + uses_polling: false - name: channel_arguments_test gtest: true build: test diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index bf1016c61ae..468b4730c69 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -686,9 +686,11 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/global_config_generic.h', 'src/core/lib/gprpp/host_port.h', 'src/core/lib/gprpp/manual_constructor.h', + 'src/core/lib/gprpp/match.h', 'src/core/lib/gprpp/memory.h', 'src/core/lib/gprpp/mpscq.h', 'src/core/lib/gprpp/orphanable.h', + 'src/core/lib/gprpp/overload.h', 'src/core/lib/gprpp/ref_counted.h', 'src/core/lib/gprpp/ref_counted_ptr.h', 'src/core/lib/gprpp/stat.h', @@ -1489,9 +1491,11 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/global_config_generic.h', 'src/core/lib/gprpp/host_port.h', 'src/core/lib/gprpp/manual_constructor.h', + 'src/core/lib/gprpp/match.h', 'src/core/lib/gprpp/memory.h', 'src/core/lib/gprpp/mpscq.h', 'src/core/lib/gprpp/orphanable.h', + 'src/core/lib/gprpp/overload.h', 'src/core/lib/gprpp/ref_counted.h', 'src/core/lib/gprpp/ref_counted_ptr.h', 'src/core/lib/gprpp/stat.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 5e5d1196bb0..86cf401ef4d 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -1083,10 +1083,12 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/host_port.cc', 'src/core/lib/gprpp/host_port.h', 'src/core/lib/gprpp/manual_constructor.h', + 'src/core/lib/gprpp/match.h', 'src/core/lib/gprpp/memory.h', 'src/core/lib/gprpp/mpscq.cc', 'src/core/lib/gprpp/mpscq.h', 'src/core/lib/gprpp/orphanable.h', + 'src/core/lib/gprpp/overload.h', 'src/core/lib/gprpp/ref_counted.h', 'src/core/lib/gprpp/ref_counted_ptr.h', 'src/core/lib/gprpp/stat.h', @@ -2087,9 +2089,11 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/global_config_generic.h', 'src/core/lib/gprpp/host_port.h', 'src/core/lib/gprpp/manual_constructor.h', + 'src/core/lib/gprpp/match.h', 'src/core/lib/gprpp/memory.h', 'src/core/lib/gprpp/mpscq.h', 'src/core/lib/gprpp/orphanable.h', + 'src/core/lib/gprpp/overload.h', 'src/core/lib/gprpp/ref_counted.h', 'src/core/lib/gprpp/ref_counted_ptr.h', 'src/core/lib/gprpp/stat.h', diff --git a/grpc.gemspec b/grpc.gemspec index ddea0a9ae6b..9ab432eb2fd 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -1002,10 +1002,12 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/gprpp/host_port.cc ) s.files += %w( src/core/lib/gprpp/host_port.h ) s.files += %w( src/core/lib/gprpp/manual_constructor.h ) + s.files += %w( src/core/lib/gprpp/match.h ) s.files += %w( src/core/lib/gprpp/memory.h ) s.files += %w( src/core/lib/gprpp/mpscq.cc ) s.files += %w( src/core/lib/gprpp/mpscq.h ) s.files += %w( src/core/lib/gprpp/orphanable.h ) + s.files += %w( src/core/lib/gprpp/overload.h ) s.files += %w( src/core/lib/gprpp/ref_counted.h ) s.files += %w( src/core/lib/gprpp/ref_counted_ptr.h ) s.files += %w( src/core/lib/gprpp/stat.h ) diff --git a/package.xml b/package.xml index 4ae0476f9e3..293a092852e 100644 --- a/package.xml +++ b/package.xml @@ -982,10 +982,12 @@ + + diff --git a/src/core/lib/avl/avl.h b/src/core/lib/avl/avl.h index 9771d845a9f..a1712a36071 100644 --- a/src/core/lib/avl/avl.h +++ b/src/core/lib/avl/avl.h @@ -22,6 +22,8 @@ #include #include +#include "absl/container/inlined_vector.h" + namespace grpc_core { template @@ -32,8 +34,12 @@ class AVL { AVL Add(K key, V value) const { return AVL(AddKey(root_, std::move(key), std::move(value))); } - AVL Remove(const K& key) const { return AVL(RemoveKey(root_, key)); } - const V* Lookup(const K& key) const { + template + AVL Remove(const SomethingLikeK& key) const { + return AVL(RemoveKey(root_, key)); + } + template + const V* Lookup(const SomethingLikeK& key) const { NodePtr n = Get(root_, key); return n ? &n->kv.second : nullptr; } @@ -50,7 +56,36 @@ class AVL { ForEachImpl(root_.get(), std::forward(f)); } - bool SameIdentity(AVL avl) const { return root_ == avl.root_; } + bool SameIdentity(const AVL& avl) const { return root_ == avl.root_; } + + bool operator==(const AVL& other) const { + Iterator a(root_); + Iterator b(other.root_); + for (;;) { + Node* p = a.current(); + Node* q = b.current(); + if (p == nullptr) return q == nullptr; + if (q == nullptr) return false; + if (p->kv != q->kv) return false; + a.MoveNext(); + b.MoveNext(); + } + } + + bool operator<(const AVL& other) const { + Iterator a(root_); + Iterator b(other.root_); + for (;;) { + Node* p = a.current(); + Node* q = b.current(); + if (p == nullptr) return q != nullptr; + if (q == nullptr) return false; + if (p->kv < q->kv) return true; + if (p->kv != q->kv) return false; + a.MoveNext(); + b.MoveNext(); + } + } private: struct Node; @@ -68,6 +103,32 @@ class AVL { }; NodePtr root_; + class Iterator { + public: + explicit Iterator(const NodePtr& root) { + auto* n = root.get(); + while (n != nullptr) { + stack_.push_back(n); + n = n->left.get(); + } + } + Node* current() const { return stack_.empty() ? nullptr : stack_.back(); } + void MoveNext() { + auto* n = stack_.back(); + stack_.pop_back(); + if (n->right != nullptr) { + n = n->right.get(); + while (n != nullptr) { + stack_.push_back(n); + n = n->left.get(); + } + } + } + + private: + absl::InlinedVector stack_; + }; + explicit AVL(NodePtr root) : root_(std::move(root)) {} template @@ -86,7 +147,8 @@ class AVL { 1 + std::max(Height(left), Height(right))); } - static NodePtr Get(const NodePtr& node, const K& key) { + template + static NodePtr Get(const NodePtr& node, const SomethingLikeK& key) { if (node == nullptr) { return nullptr; } @@ -198,7 +260,8 @@ class AVL { return node; } - static NodePtr RemoveKey(const NodePtr& node, const K& key) { + template + static NodePtr RemoveKey(const NodePtr& node, const SomethingLikeK& key) { if (node == nullptr) { return nullptr; } diff --git a/src/core/lib/channel/channel_args.cc b/src/core/lib/channel/channel_args.cc index ab256024280..2ae1bd9e625 100644 --- a/src/core/lib/channel/channel_args.cc +++ b/src/core/lib/channel/channel_args.cc @@ -37,6 +37,104 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/match.h" + +static int cmp_ptr(void* a_ptr, const grpc_arg_pointer_vtable* a_vtable, + void* b_ptr, const grpc_arg_pointer_vtable* b_vtable) { + int c = grpc_core::QsortCompare(a_ptr, b_ptr); + if (c == 0) return 0; + c = grpc_core::QsortCompare(a_vtable, b_vtable); + if (c != 0) return c; + return a_vtable->cmp(a_ptr, b_ptr); +} + +namespace grpc_core { + +bool ChannelArgs::Pointer::operator==(const Pointer& rhs) const { + return cmp_ptr(p_, vtable_, rhs.p_, rhs.vtable_) == 0; +} + +bool ChannelArgs::Pointer::operator<(const Pointer& rhs) const { + return cmp_ptr(p_, vtable_, rhs.p_, rhs.vtable_) < 0; +} + +ChannelArgs::ChannelArgs() = default; + +ChannelArgs ChannelArgs::Set(grpc_arg arg) const { + switch (arg.type) { + case GRPC_ARG_INTEGER: + return Set(arg.key, arg.value.integer); + case GRPC_ARG_STRING: + if (arg.value.string != nullptr) return Set(arg.key, arg.value.string); + return Set(arg.key, ""); + case GRPC_ARG_POINTER: + return Set(arg.key, + Pointer(arg.value.pointer.vtable->copy(arg.value.pointer.p), + arg.value.pointer.vtable)); + } + GPR_UNREACHABLE_CODE(return ChannelArgs()); +} + +ChannelArgs ChannelArgs::FromC(const grpc_channel_args* args) { + ChannelArgs result; + if (args != nullptr) { + for (size_t i = 0; i < args->num_args; i++) { + result = result.Set(args->args[i]); + } + } + return result; +} + +const grpc_channel_args* ChannelArgs::ToC() const { + std::vector c_args; + args_.ForEach([&c_args](const std::string& key, const Value& value) { + char* name = const_cast(key.c_str()); + c_args.push_back(Match( + value, + [name](int i) { return grpc_channel_arg_integer_create(name, i); }, + [name](const std::string& s) { + return grpc_channel_arg_string_create(name, + const_cast(s.c_str())); + }, + [name](const Pointer& p) { + return grpc_channel_arg_pointer_create(name, p.c_pointer(), + p.c_vtable()); + })); + }); + return grpc_channel_args_copy_and_add(nullptr, c_args.data(), c_args.size()); +} + +ChannelArgs ChannelArgs::Set(absl::string_view key, Value value) const { + return ChannelArgs(args_.Add(std::string(key), std::move(value))); +} + +ChannelArgs ChannelArgs::Remove(absl::string_view key) const { + return ChannelArgs(args_.Remove(key)); +} + +absl::optional ChannelArgs::GetInt(absl::string_view name) const { + auto* v = Get(name); + if (v == nullptr) return absl::nullopt; + if (!absl::holds_alternative(*v)) return absl::nullopt; + return absl::get(*v); +} + +absl::optional ChannelArgs::GetString( + absl::string_view name) const { + auto* v = Get(name); + if (v == nullptr) return absl::nullopt; + if (!absl::holds_alternative(*v)) return absl::nullopt; + return absl::get(*v); +} + +void* ChannelArgs::GetVoidPointer(absl::string_view name) const { + auto* v = Get(name); + if (v == nullptr) return nullptr; + if (!absl::holds_alternative(*v)) return nullptr; + return absl::get(*v).c_pointer(); +} + +} // namespace grpc_core static grpc_arg copy_arg(const grpc_arg* src) { grpc_arg dst; @@ -156,16 +254,8 @@ static int cmp_arg(const grpc_arg* a, const grpc_arg* b) { case GRPC_ARG_INTEGER: return grpc_core::QsortCompare(a->value.integer, b->value.integer); case GRPC_ARG_POINTER: - c = grpc_core::QsortCompare(a->value.pointer.p, b->value.pointer.p); - if (c != 0) { - c = grpc_core::QsortCompare(a->value.pointer.vtable, - b->value.pointer.vtable); - if (c == 0) { - c = a->value.pointer.vtable->cmp(a->value.pointer.p, - b->value.pointer.p); - } - } - return c; + return cmp_ptr(a->value.pointer.p, a->value.pointer.vtable, + b->value.pointer.p, b->value.pointer.vtable); } GPR_UNREACHABLE_CODE(return 0); } @@ -384,9 +474,9 @@ const grpc_channel_args* RemoveGrpcInternalArgs(const grpc_channel_args* src) { return dst; } -const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src) { - if (src == nullptr) return nullptr; - std::map values; +ChannelArgs UniquifyChannelArgKeys(const grpc_channel_args* src) { + if (src == nullptr) return ChannelArgs(); + ChannelArgs output; std::map> concatenated_values; for (size_t i = 0; i < src->num_args; i++) { absl::string_view key = src->args[i].key; @@ -401,46 +491,23 @@ const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src) { concatenated_values[key].push_back(src->args[i].value.string); } continue; + } else if (absl::StartsWith(key, "grpc.internal.")) { + continue; } - auto it = values.find(key); - if (it == values.end()) { - values[key] = &src->args[i]; + if (!output.Contains(key)) { + output = output.Set(src->args[i]); } else { // Traditional grpc_channel_args_find behavior was to pick the first // value. // For compatibility with existing users, we will do the same here. } } - if (values.size() + concatenated_values.size() == src->num_args) { - return grpc_channel_args_copy(src); - } // Concatenate the concatenated values. - std::map concatenated_values_str; for (const auto& concatenated_value : concatenated_values) { - concatenated_values_str[concatenated_value.first] = - absl::StrJoin(concatenated_value.second, " "); - } - // Create the result - std::vector argv; - argv.reserve(values.size()); - for (const auto& a : values) { - argv.push_back(*a.second); - } - for (const auto& a : concatenated_values_str) { - argv.push_back( - grpc_channel_arg_string_create(const_cast(a.first.data()), - const_cast(a.second.c_str()))); + output = output.Set(concatenated_value.first, + absl::StrJoin(concatenated_value.second, " ")); } - grpc_channel_args args = {argv.size(), argv.data()}; - // Log that we're mutating things - gpr_log(GPR_INFO, - "Uniquification pass on channel args is mutating them: {%s} is being " - "changed to {%s}", - grpc_channel_args_string(src).c_str(), - grpc_channel_args_string(&args).c_str()); - // Return the result (note we need to copy because we're borrowing the args - // from src still!) - return grpc_channel_args_copy(&args); + return output; } } // namespace grpc_core diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 48007f1e84f..12c3933859b 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -23,10 +23,170 @@ #include +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" + #include +#include "src/core/lib/avl/avl.h" +#include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/surface/channel_stack_type.h" +namespace grpc_core { + +// Define a traits object for vtable lookup - allows us to integrate with +// existing code easily (just define the trait!) and allows some magic in +// ChannelArgs to automatically derive a vtable from a T*. +// To participate as a pointer, instances should expose the function: +// // Gets the vtable for this type +// static const grpc_channel_arg_vtable* vtable(); +// // Performs any mutations required for channel args to own a pointer +// static void* take_unowned_pointer(T* p); +template +struct ChannelArgTypeTraits; + +template +struct ChannelArgTypeTraits< + T, absl::enable_if_t, T>::value, void>> { + static const grpc_arg_pointer_vtable* vtable() { + static const grpc_arg_pointer_vtable tbl = { + // copy + [](void* p) -> void* { return static_cast(p)->Ref().release(); }, + // destroy + [](void* p) { static_cast(p)->Unref(); }, + // compare + [](void* p1, void* p2) { + return QsortCompare(*static_cast(p1), + *static_cast(p2)); + }, + }; + return &tbl; + }; +}; + +class ChannelArgs { + public: + class Pointer { + public: + Pointer(void* p, const grpc_arg_pointer_vtable* vtable) + : p_(p), vtable_(vtable == nullptr ? empty_vtable() : vtable) {} + ~Pointer() { vtable_->destroy(p_); } + + Pointer(const Pointer& other) + : p_(other.vtable_->copy(other.p_)), vtable_(other.vtable_) {} + Pointer& operator=(Pointer other) { + std::swap(p_, other.p_); + std::swap(vtable_, other.vtable_); + return *this; + } + Pointer(Pointer&& other) noexcept : p_(other.p_), vtable_(other.vtable_) { + other.p_ = nullptr; + other.vtable_ = empty_vtable(); + } + Pointer& operator=(Pointer&& other) noexcept { + std::swap(p_, other.p_); + std::swap(vtable_, other.vtable_); + return *this; + } + + bool operator==(const Pointer& rhs) const; + bool operator<(const Pointer& rhs) const; + bool operator!=(const Pointer& rhs) const { return !(*this == rhs); } + + void* c_pointer() const { return p_; } + + const grpc_arg_pointer_vtable* c_vtable() const { return vtable_; } + + private: + void* p_; + const grpc_arg_pointer_vtable* vtable_; + static const grpc_arg_pointer_vtable* empty_vtable() { + static const grpc_arg_pointer_vtable vtable = { + // copy + [](void* p) { return p; }, + // destroy + [](void*) {}, + // cmp + [](void* p1, void* p2) -> int { return QsortCompare(p1, p2); }, + }; + return &vtable; + } + }; + using Value = absl::variant; + + ChannelArgs(); + + static ChannelArgs FromC(const grpc_channel_args* args); + const grpc_channel_args* ToC() const; + + const Value* Get(absl::string_view name) const { return args_.Lookup(name); } + GRPC_MUST_USE_RESULT ChannelArgs Set(absl::string_view name, + Value value) const; + GRPC_MUST_USE_RESULT ChannelArgs Set(grpc_arg arg) const; + template + GRPC_MUST_USE_RESULT absl::enable_if_t< + std::is_same::vtable())>::value, + ChannelArgs> + Set(absl::string_view name, T* value) const { + return Set(name, + Pointer(ChannelArgTypeTraits::take_unowned_pointer(value), + ChannelArgTypeTraits::vtable())); + } + template + GRPC_MUST_USE_RESULT absl::enable_if_t< + std::is_same::vtable())>::value, + ChannelArgs> + Set(absl::string_view name, RefCountedPtr value) const { + return Set(name, + Pointer(value.release(), ChannelArgTypeTraits::vtable())); + } + GRPC_MUST_USE_RESULT ChannelArgs Remove(absl::string_view name) const; + bool Contains(absl::string_view name) const { return Get(name) != nullptr; } + + absl::optional GetInt(absl::string_view name) const; + absl::optional GetString(absl::string_view name) const; + void* GetVoidPointer(absl::string_view name) const; + template + T* GetPointer(absl::string_view name) const { + return static_cast(GetVoidPointer(name)); + } + + // Object based get/set. + // Deal with the common case that we set a pointer to an object under + // the same name in every usage. + // Expects ChannelArgTypeTraits to exist for T, and T to expose: + // static string_view channel_arg_name(); + template + GRPC_MUST_USE_RESULT ChannelArgs SetObject(T* p) const { + return Set(T::channel_arg_name(), p); + } + template + GRPC_MUST_USE_RESULT ChannelArgs SetObject(RefCountedPtr p) const { + return Set(T::channel_arg_name(), std::move(p)); + } + template + T* GetObject() { + return GetPointer(T::channel_arg_name()); + } + + bool operator<(const ChannelArgs& other) const { return args_ < other.args_; } + bool operator==(const ChannelArgs& other) const { + return args_ == other.args_; + } + + private: + explicit ChannelArgs(AVL args) : args_(args) {} + + AVL args_; +}; + +} // namespace grpc_core + // Channel args are intentionally immutable, to avoid the need for locking. /** Copy the arguments in \a src into a new instance */ @@ -120,15 +280,9 @@ grpc_arg grpc_channel_arg_pointer_create(char* name, void* value, std::string grpc_channel_args_string(const grpc_channel_args* args); namespace grpc_core { -/** Remove any channel args prefixed with 'grpc.internal.' - * These are used for internal implementation details and are not intended to - * be exposed to users. - * Returns a new channel args instance. - * Does not take ownership of \a src. - * Should be called by any public API that receives channel args. */ -const grpc_channel_args* RemoveGrpcInternalArgs(const grpc_channel_args* src); -/** Ensure no duplicate channel args, in preparation for moving to a map<> */ -const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src); +/** Ensure no duplicate channel args (with some backwards compatibility hacks), + * and return a C++ object */ +ChannelArgs UniquifyChannelArgKeys(const grpc_channel_args* src); } // namespace grpc_core // Takes ownership of the old_args diff --git a/src/core/lib/channel/channel_args_preconditioning.cc b/src/core/lib/channel/channel_args_preconditioning.cc index 640ca58b9da..e121f715586 100644 --- a/src/core/lib/channel/channel_args_preconditioning.cc +++ b/src/core/lib/channel/channel_args_preconditioning.cc @@ -25,10 +25,6 @@ void ChannelArgsPreconditioning::Builder::RegisterStage(Stage stage) { } ChannelArgsPreconditioning ChannelArgsPreconditioning::Builder::Build() { - // TODO(ctiller): should probably make this registered too. - stages_.emplace_back(RemoveGrpcInternalArgs); - stages_.emplace_back(UniquifyChannelArgKeys); - ChannelArgsPreconditioning preconditioning; preconditioning.stages_ = std::move(stages_); return preconditioning; @@ -36,13 +32,11 @@ ChannelArgsPreconditioning ChannelArgsPreconditioning::Builder::Build() { const grpc_channel_args* ChannelArgsPreconditioning::PreconditionChannelArgs( const grpc_channel_args* args) const { - const grpc_channel_args* owned_args = nullptr; + ChannelArgs channel_args = UniquifyChannelArgKeys(args); for (auto& stage : stages_) { - args = stage(args); - grpc_channel_args_destroy(owned_args); - owned_args = args; + channel_args = stage(std::move(channel_args)); } - return args; + return channel_args.ToC(); } } // namespace grpc_core diff --git a/src/core/lib/channel/channel_args_preconditioning.h b/src/core/lib/channel/channel_args_preconditioning.h index 224399fb549..06a4b5e78fc 100644 --- a/src/core/lib/channel/channel_args_preconditioning.h +++ b/src/core/lib/channel/channel_args_preconditioning.h @@ -33,8 +33,7 @@ class ChannelArgsPreconditioning { // Take channel args and mutate them. // Does not take ownership of the channel args passed in. // Returns a new channel args object that is owned by the caller. - using Stage = - std::function; + using Stage = std::function; class Builder { public: diff --git a/src/core/lib/resource_quota/api.cc b/src/core/lib/resource_quota/api.cc index efbd1737a55..cc2a772df65 100644 --- a/src/core/lib/resource_quota/api.cc +++ b/src/core/lib/resource_quota/api.cc @@ -20,6 +20,7 @@ #include "src/core/lib/gpr/useful.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/resource_quota/resource_quota.h" namespace grpc_core { @@ -30,30 +31,13 @@ ResourceQuotaRefPtr ResourceQuotaFromChannelArgs( ->Ref(); } -namespace { -grpc_arg MakeArg(ResourceQuota* quota) { - return grpc_channel_arg_pointer_create( - const_cast(GRPC_ARG_RESOURCE_QUOTA), quota, - grpc_resource_quota_arg_vtable()); -} - -const grpc_channel_args* EnsureResourceQuotaInChannelArgs( - const grpc_channel_args* args) { - const grpc_arg* existing = - grpc_channel_args_find(args, GRPC_ARG_RESOURCE_QUOTA); - if (existing != nullptr && existing->type == GRPC_ARG_POINTER && - existing->value.pointer.p != nullptr) { - return grpc_channel_args_copy(args); - } +ChannelArgs EnsureResourceQuotaInChannelArgs(ChannelArgs args) { + if (args.GetObject() != nullptr) return args; // If there's no existing quota, add it to the default one - shared between // all channel args declared thusly. This prevents us from accidentally not // sharing subchannels due to their channel args not specifying a quota. - const char* remove[] = {GRPC_ARG_RESOURCE_QUOTA}; - auto new_arg = MakeArg(ResourceQuota::Default().get()); - return grpc_channel_args_copy_and_add_and_remove(args, remove, 1, &new_arg, - 1); + return args.SetObject(ResourceQuota::Default()); } -} // namespace void RegisterResourceQuota(CoreConfiguration::Builder* builder) { builder->channel_args_preconditioning()->RegisterStage( @@ -63,16 +47,7 @@ void RegisterResourceQuota(CoreConfiguration::Builder* builder) { } // namespace grpc_core extern "C" const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable() { - static const grpc_arg_pointer_vtable vtable = { - // copy - [](void* p) -> void* { - return static_cast(p)->Ref().release(); - }, - // destroy - [](void* p) { static_cast(p)->Unref(); }, - // compare - [](void* p, void* q) { return grpc_core::QsortCompare(p, q); }}; - return &vtable; + return grpc_core::ChannelArgTypeTraits::vtable(); } extern "C" grpc_resource_quota* grpc_resource_quota_create(const char* name) { diff --git a/src/core/lib/resource_quota/resource_quota.h b/src/core/lib/resource_quota/resource_quota.h index 28a6156ea59..4ded3ec1a4f 100644 --- a/src/core/lib/resource_quota/resource_quota.h +++ b/src/core/lib/resource_quota/resource_quota.h @@ -37,6 +37,10 @@ class ResourceQuota : public RefCounted, ResourceQuota(const ResourceQuota&) = delete; ResourceQuota& operator=(const ResourceQuota&) = delete; + static absl::string_view channel_arg_name() { + return GRPC_ARG_RESOURCE_QUOTA; + } + MemoryQuotaRefPtr memory_quota() { return memory_quota_; } const RefCountedPtr& thread_quota() { return thread_quota_; } @@ -44,6 +48,8 @@ class ResourceQuota : public RefCounted, // The default global resource quota static ResourceQuotaRefPtr Default(); + bool operator<(const ResourceQuota& other) const { return this < &other; } + private: MemoryQuotaRefPtr memory_quota_; RefCountedPtr thread_quota_; diff --git a/test/core/avl/avl_fuzzer.cc b/test/core/avl/avl_fuzzer.cc index 109f64fe2be..dcc381cdf3f 100644 --- a/test/core/avl/avl_fuzzer.cc +++ b/test/core/avl/avl_fuzzer.cc @@ -23,29 +23,27 @@ namespace grpc_core { class Fuzzer { public: - void Run(const avl_fuzzer::Msg& msg) { - CheckEqual(); - for (const auto& action : msg.actions()) { - switch (action.action_case()) { - case avl_fuzzer::Action::kSet: - avl_ = avl_.Add(action.key(), action.set()); - map_[action.key()] = action.set(); - break; - case avl_fuzzer::Action::kDel: - avl_ = avl_.Remove(action.key()); - map_.erase(action.key()); - break; - case avl_fuzzer::Action::kGet: { - auto* p = avl_.Lookup(action.key()); - auto it = map_.find(action.key()); - if (it == map_.end() && p != nullptr) abort(); - if (it != map_.end() && p == nullptr) abort(); - if (it != map_.end() && it->second != *p) abort(); - } break; - case avl_fuzzer::Action::ACTION_NOT_SET: - break; - } - CheckEqual(); + Fuzzer() { CheckEqual(); } + ~Fuzzer() { CheckEqual(); } + void Run(const avl_fuzzer::Action& action) { + switch (action.action_case()) { + case avl_fuzzer::Action::kSet: + avl_ = avl_.Add(action.key(), action.set()); + map_[action.key()] = action.set(); + break; + case avl_fuzzer::Action::kDel: + avl_ = avl_.Remove(action.key()); + map_.erase(action.key()); + break; + case avl_fuzzer::Action::kGet: { + auto* p = avl_.Lookup(action.key()); + auto it = map_.find(action.key()); + if (it == map_.end() && p != nullptr) abort(); + if (it != map_.end() && p == nullptr) abort(); + if (it != map_.end() && it->second != *p) abort(); + } break; + case avl_fuzzer::Action::ACTION_NOT_SET: + break; } } @@ -65,8 +63,38 @@ class Fuzzer { std::map map_; }; +AVL AvlFromProto( + const ::google::protobuf::RepeatedPtrField& p) { + AVL a; + for (const auto& kv : p) { + a = a.Add(kv.key(), kv.value()); + } + return a; +} + +std::map MapFromProto( + const ::google::protobuf::RepeatedPtrField& p) { + std::map a; + for (const auto& kv : p) { + a[kv.key()] = kv.value(); + } + return a; +} + } // namespace grpc_core DEFINE_PROTO_FUZZER(const avl_fuzzer::Msg& msg) { - grpc_core::Fuzzer().Run(msg); + grpc_core::Fuzzer fuzzer; + for (const auto& action : msg.actions()) { + grpc_core::Fuzzer().Run(action); + } + + for (const auto& cmp : msg.compares()) { + auto left_avl = grpc_core::AvlFromProto(cmp.left()); + auto left_map = grpc_core::MapFromProto(cmp.left()); + auto right_avl = grpc_core::AvlFromProto(cmp.right()); + auto right_map = grpc_core::MapFromProto(cmp.right()); + if ((left_avl == right_avl) != (left_map == right_map)) abort(); + if ((left_avl < right_avl) != (left_map < right_map)) abort(); + } } diff --git a/test/core/avl/avl_fuzzer.proto b/test/core/avl/avl_fuzzer.proto index 74a613c2a8b..ec05fe313d2 100644 --- a/test/core/avl/avl_fuzzer.proto +++ b/test/core/avl/avl_fuzzer.proto @@ -27,6 +27,17 @@ message Action { } } +message KeyValue { + int32 key = 1; + int32 value = 2; +} + +message Compares { + repeated KeyValue left = 1; + repeated KeyValue right = 2; +} + message Msg { repeated Action actions = 2; + repeated Compares compares = 3; } diff --git a/test/core/avl/avl_fuzzer_corpus/crash-060a9a897130ba7bb2f4313daa604c47f7c7c907 b/test/core/avl/avl_fuzzer_corpus/crash-060a9a897130ba7bb2f4313daa604c47f7c7c907 new file mode 100644 index 00000000000..cf46495b8aa --- /dev/null +++ b/test/core/avl/avl_fuzzer_corpus/crash-060a9a897130ba7bb2f4313daa604c47f7c7c907 @@ -0,0 +1,9 @@ +actions { + del { + } +} +compares { + left { + key: 50397184 + } +} diff --git a/test/core/avl/avl_fuzzer_corpus/crash-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360 b/test/core/avl/avl_fuzzer_corpus/crash-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360 new file mode 100644 index 00000000000..c621adbddce --- /dev/null +++ b/test/core/avl/avl_fuzzer_corpus/crash-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360 @@ -0,0 +1,5 @@ +compares { + right { + key: 805306368 + } +} diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD index f91e914693e..6b4e37add48 100644 --- a/test/core/channel/BUILD +++ b/test/core/channel/BUILD @@ -21,6 +21,7 @@ licenses(["notice"]) grpc_cc_test( name = "channel_args_test", srcs = ["channel_args_test.cc"], + external_deps = ["gtest"], language = "C++", uses_polling = False, deps = [ diff --git a/test/core/channel/channel_args_test.cc b/test/core/channel/channel_args_test.cc index efcf5047cc1..44688540d0b 100644 --- a/test/core/channel/channel_args_test.cc +++ b/test/core/channel/channel_args_test.cc @@ -20,6 +20,8 @@ #include +#include + #include #include #include @@ -27,11 +29,101 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/surface/channel.h" #include "test/core/util/test_config.h" -static void test_create(void) { +namespace grpc_core { + +TEST(ChannelArgsTest, Noop) { ChannelArgs(); } + +TEST(ChannelArgsTest, SetGetRemove) { + const grpc_arg_pointer_vtable malloc_vtable = { + // copy + [](void* p) { return p; }, + // destroy + [](void*) {}, + // equal + [](void* p1, void* p2) { return QsortCompare(p1, p2); }, + }; + void* ptr = gpr_malloc(42); + + ChannelArgs a; + ChannelArgs b = a.Set("answer", 42); + ChannelArgs c = b.Set("foo", "bar"); + ChannelArgs d = c.Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable)); + ChannelArgs e = d.Set("alpha", "beta"); + ChannelArgs f = e.Remove("answer"); + EXPECT_EQ(a.Get("answer"), nullptr); + EXPECT_EQ(*b.Get("answer"), ChannelArgs::Value(42)); + EXPECT_EQ(*c.Get("answer"), ChannelArgs::Value(42)); + EXPECT_EQ(c.GetInt("answer"), 42); + EXPECT_EQ(c.GetString("answer"), absl::nullopt); + EXPECT_EQ(f.Get("answer"), nullptr); + EXPECT_EQ(*c.Get("foo"), ChannelArgs::Value("bar")); + EXPECT_EQ(c.GetString("foo"), "bar"); + EXPECT_EQ(c.GetString("answer"), absl::nullopt); + EXPECT_EQ(*d.Get("ptr"), + ChannelArgs::Value(ChannelArgs::Pointer(ptr, &malloc_vtable))); + EXPECT_EQ(*e.Get("alpha"), ChannelArgs::Value("beta")); + gpr_free(ptr); +} + +TEST(ChannelArgsTest, StoreRefCountedPtr) { + struct Test : public RefCounted { + explicit Test(int n) : n(n) {} + int n; + bool operator<(const Test& rhs) const { return n < rhs.n; } + }; + auto p = MakeRefCounted(123); + + ChannelArgs a; + a = a.Set("test", std::move(p)); + EXPECT_EQ(a.GetPointer("test")->n, 123); +} + +TEST(ChannelArgsTest, ObjectApi) { + struct MyFancyObject : public RefCounted { + explicit MyFancyObject(int n) : n(n) {} + static absl::string_view channel_arg_name() { + return "grpc.internal.my-fancy-object"; + } + int n; + bool operator<(const MyFancyObject& rhs) const { return n < rhs.n; } + }; + auto p = MakeRefCounted(42); + ChannelArgs a; + a = a.SetObject(std::move(p)); + EXPECT_EQ(a.GetObject()->n, 42); +} + +TEST(ChannelArgsTest, ToAndFromC) { + const grpc_arg_pointer_vtable malloc_vtable = { + // copy + [](void* p) { return p; }, + // destroy + [](void*) {}, + // equal + [](void* p1, void* p2) { return QsortCompare(p1, p2); }, + }; + void* ptr = gpr_malloc(42); + ChannelArgs a = ChannelArgs() + .Set("answer", 42) + .Set("foo", "bar") + .Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable)) + .Set("alpha", "beta"); + const grpc_channel_args* c = a.ToC(); + ChannelArgs b = ChannelArgs::FromC(c); + grpc_channel_args_destroy(c); + EXPECT_EQ(a, b); + gpr_free(ptr); +} + +} // namespace grpc_core + +TEST(GrpcChannelArgsTest, Create) { grpc_core::ExecCtx exec_ctx; grpc_arg to_add[2]; grpc_channel_args* ch_args; @@ -80,7 +172,7 @@ static int fake_pointer_cmp(void* a, void* b) { static const grpc_arg_pointer_vtable fake_pointer_arg_vtable = { fake_pointer_arg_copy, fake_pointer_arg_destroy, fake_pointer_cmp}; -static void test_channel_create_with_args(void) { +TEST(GrpcChannelArgsTest, ChannelCreateWithArgs) { grpc_arg client_a[3]; client_a[0] = @@ -131,53 +223,7 @@ grpc_channel_args* mutate_channel_args(const char* target, return new_args; } -// Minimal stack should not have client_idle filter -static bool channel_has_client_idle_filter(grpc_channel* c) { - grpc_channel_stack* stack = grpc_channel_get_channel_stack(c); - for (size_t i = 0; i < stack->count; i++) { - if (strcmp(grpc_channel_stack_element(stack, i)->filter->name, - "client_idle") == 0) { - return true; - } - } - return false; -} - -static void test_channel_create_with_global_mutator(void) { - grpc_channel_args_set_client_channel_creation_mutator(mutate_channel_args); - // We also add some custom args to make sure the ownership is correct. - grpc_arg client_a[3]; - - client_a[0] = - grpc_channel_arg_integer_create(const_cast("arg_int"), 0); - client_a[1] = grpc_channel_arg_string_create( - const_cast("arg_str"), const_cast("arg_str_val")); - // allocated and adds custom pointer arg - fake_class* fc = static_cast(gpr_malloc(sizeof(fake_class))); - fc->foo = 42; - client_a[2] = grpc_channel_arg_pointer_create( - const_cast("arg_pointer"), fc, &fake_pointer_arg_vtable); - - // creates channels - grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; - grpc_channel_credentials* creds = grpc_insecure_credentials_create(); - grpc_channel* c = grpc_channel_create("no_op_mutator", creds, &client_args); - grpc_channel_credentials_release(creds); - GPR_ASSERT(channel_has_client_idle_filter(c)); - grpc_channel_destroy(c); - - grpc_channel_credentials* another_creds = grpc_insecure_credentials_create(); - c = grpc_channel_create("minimal_stack_mutator", another_creds, &client_args); - grpc_channel_credentials_release(another_creds); - GPR_ASSERT(channel_has_client_idle_filter(c) == false); - grpc_channel_destroy(c); - - gpr_free(fc); - auto mutator = grpc_channel_args_get_client_channel_creation_mutator(); - GPR_ASSERT(mutator == &mutate_channel_args); -} - -static void test_server_create_with_args(void) { +TEST(GrpcChannelArgsTest, TestServerCreateWithArgs) { grpc_arg server_a[3]; // adds integer arg @@ -207,14 +253,10 @@ static void test_server_create_with_args(void) { } int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); grpc::testing::TestEnvironment env(argc, argv); grpc_init(); - test_create(); - test_channel_create_with_args(); - test_server_create_with_args(); - // This has to be the last test. - // TODO(markdroth): re-enable this test once client_idle is re-enabled - // test_channel_create_with_global_mutator(); + auto r = RUN_ALL_TESTS(); grpc_shutdown(); - return 0; + return r; } diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 669e40284a3..cd9f5422f91 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1981,10 +1981,12 @@ src/core/lib/gprpp/global_config_generic.h \ src/core/lib/gprpp/host_port.cc \ src/core/lib/gprpp/host_port.h \ src/core/lib/gprpp/manual_constructor.h \ +src/core/lib/gprpp/match.h \ src/core/lib/gprpp/memory.h \ src/core/lib/gprpp/mpscq.cc \ src/core/lib/gprpp/mpscq.h \ src/core/lib/gprpp/orphanable.h \ +src/core/lib/gprpp/overload.h \ src/core/lib/gprpp/ref_counted.h \ src/core/lib/gprpp/ref_counted_ptr.h \ src/core/lib/gprpp/stat.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 19179d843a8..d32ecb7fa9e 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1775,10 +1775,12 @@ src/core/lib/gprpp/global_config_generic.h \ src/core/lib/gprpp/host_port.cc \ src/core/lib/gprpp/host_port.h \ src/core/lib/gprpp/manual_constructor.h \ +src/core/lib/gprpp/match.h \ src/core/lib/gprpp/memory.h \ src/core/lib/gprpp/mpscq.cc \ src/core/lib/gprpp/mpscq.h \ src/core/lib/gprpp/orphanable.h \ +src/core/lib/gprpp/overload.h \ src/core/lib/gprpp/ref_counted.h \ src/core/lib/gprpp/ref_counted_ptr.h \ src/core/lib/gprpp/stat.h \ diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 1d7be30f956..8d81d9dfcd2 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -525,30 +525,6 @@ ], "uses_polling": true }, - { - "args": [], - "benchmark": false, - "ci_platforms": [ - "linux", - "mac", - "posix", - "windows" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "gtest": false, - "language": "c", - "name": "channel_args_test", - "platforms": [ - "linux", - "mac", - "posix", - "windows" - ], - "uses_polling": false - }, { "args": [], "benchmark": false, @@ -3303,6 +3279,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "channel_args_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [], "benchmark": false,