proto_utils_test.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. *
  3. * Copyright 2017 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <gtest/gtest.h>
  19. #include <grpc/impl/codegen/byte_buffer.h>
  20. #include <grpc/slice.h>
  21. #include <grpcpp/impl/codegen/grpc_library.h>
  22. #include <grpcpp/impl/codegen/proto_utils.h>
  23. #include <grpcpp/impl/grpc_library.h>
  24. #include "test/core/util/test_config.h"
  25. namespace grpc {
  26. namespace internal {
  27. // Provide access to ProtoBufferWriter internals.
  28. class ProtoBufferWriterPeer {
  29. public:
  30. explicit ProtoBufferWriterPeer(ProtoBufferWriter* writer) : writer_(writer) {}
  31. bool have_backup() const { return writer_->have_backup_; }
  32. const grpc_slice& backup_slice() const { return writer_->backup_slice_; }
  33. const grpc_slice& slice() const { return writer_->slice_; }
  34. private:
  35. ProtoBufferWriter* writer_;
  36. };
  37. // Provide access to ByteBuffer internals.
  38. class GrpcByteBufferPeer {
  39. public:
  40. explicit GrpcByteBufferPeer(ByteBuffer* bb) : bb_(bb) {}
  41. grpc_byte_buffer* c_buffer() { return bb_->c_buffer(); }
  42. private:
  43. ByteBuffer* bb_;
  44. };
  45. class ProtoUtilsTest : public ::testing::Test {
  46. protected:
  47. static void SetUpTestCase() {
  48. // Ensure the ProtoBufferWriter internals are initialized.
  49. grpc::internal::GrpcLibraryInitializer init;
  50. init.summon();
  51. grpc::GrpcLibraryCodegen lib;
  52. grpc_init();
  53. }
  54. static void TearDownTestCase() { grpc_shutdown(); }
  55. };
  56. // Regression test for a memory corruption bug where a series of
  57. // ProtoBufferWriter Next()/Backup() invocations could result in a dangling
  58. // pointer returned by Next() due to the interaction between grpc_slice inlining
  59. // and GRPC_SLICE_START_PTR.
  60. TEST_F(ProtoUtilsTest, TinyBackupThenNext) {
  61. ByteBuffer bp;
  62. const int block_size = 1024;
  63. ProtoBufferWriter writer(&bp, block_size, 8192);
  64. ProtoBufferWriterPeer peer(&writer);
  65. void* data;
  66. int size;
  67. // Allocate a slice.
  68. ASSERT_TRUE(writer.Next(&data, &size));
  69. EXPECT_EQ(block_size, size);
  70. // Return a single byte.
  71. writer.BackUp(1);
  72. EXPECT_FALSE(peer.have_backup());
  73. // On the next allocation, the returned slice is non-inlined.
  74. ASSERT_TRUE(writer.Next(&data, &size));
  75. EXPECT_TRUE(peer.slice().refcount != nullptr);
  76. EXPECT_EQ(block_size, size);
  77. }
  78. namespace {
  79. // Set backup_size to 0 to indicate no backup is needed.
  80. void BufferWriterTest(int block_size, int total_size, int backup_size) {
  81. ByteBuffer bb;
  82. ProtoBufferWriter writer(&bb, block_size, total_size);
  83. int written_size = 0;
  84. void* data;
  85. int size = 0;
  86. bool backed_up_entire_slice = false;
  87. while (written_size < total_size) {
  88. EXPECT_TRUE(writer.Next(&data, &size));
  89. EXPECT_GT(size, 0);
  90. EXPECT_TRUE(data);
  91. int write_size = size;
  92. bool should_backup = false;
  93. if (backup_size > 0 && size > backup_size) {
  94. write_size = size - backup_size;
  95. should_backup = true;
  96. } else if (size == backup_size && !backed_up_entire_slice) {
  97. // only backup entire slice once.
  98. backed_up_entire_slice = true;
  99. should_backup = true;
  100. write_size = 0;
  101. }
  102. // May need a last backup.
  103. if (write_size + written_size > total_size) {
  104. write_size = total_size - written_size;
  105. should_backup = true;
  106. backup_size = size - write_size;
  107. ASSERT_GT(backup_size, 0);
  108. }
  109. for (int i = 0; i < write_size; i++) {
  110. (static_cast<uint8_t*>(data))[i] = written_size % 128;
  111. written_size++;
  112. }
  113. if (should_backup) {
  114. writer.BackUp(backup_size);
  115. }
  116. }
  117. EXPECT_EQ(bb.Length(), (size_t)total_size);
  118. grpc_byte_buffer_reader reader;
  119. GrpcByteBufferPeer peer(&bb);
  120. grpc_byte_buffer_reader_init(&reader, peer.c_buffer());
  121. int read_bytes = 0;
  122. while (read_bytes < total_size) {
  123. grpc_slice s;
  124. EXPECT_TRUE(grpc_byte_buffer_reader_next(&reader, &s));
  125. for (size_t i = 0; i < GRPC_SLICE_LENGTH(s); i++) {
  126. EXPECT_EQ(GRPC_SLICE_START_PTR(s)[i], read_bytes % 128);
  127. read_bytes++;
  128. }
  129. grpc_slice_unref(s);
  130. }
  131. EXPECT_EQ(read_bytes, total_size);
  132. grpc_byte_buffer_reader_destroy(&reader);
  133. }
  134. class WriterTest : public ::testing::Test {
  135. protected:
  136. static void SetUpTestCase() {
  137. grpc::internal::GrpcLibraryInitializer init;
  138. init.summon();
  139. grpc::GrpcLibraryCodegen lib;
  140. // Ensure the ProtoBufferWriter internals are initialized.
  141. grpc_init();
  142. }
  143. static void TearDownTestCase() { grpc_shutdown(); }
  144. };
  145. TEST_F(WriterTest, TinyBlockTinyBackup) {
  146. for (int i = 2; i < static_cast<int> GRPC_SLICE_INLINED_SIZE; i++) {
  147. BufferWriterTest(i, 256, 1);
  148. }
  149. }
  150. TEST_F(WriterTest, SmallBlockTinyBackup) { BufferWriterTest(64, 256, 1); }
  151. TEST_F(WriterTest, SmallBlockNoBackup) { BufferWriterTest(64, 256, 0); }
  152. TEST_F(WriterTest, SmallBlockFullBackup) { BufferWriterTest(64, 256, 64); }
  153. TEST_F(WriterTest, LargeBlockTinyBackup) { BufferWriterTest(4096, 8192, 1); }
  154. TEST_F(WriterTest, LargeBlockNoBackup) { BufferWriterTest(4096, 8192, 0); }
  155. TEST_F(WriterTest, LargeBlockFullBackup) { BufferWriterTest(4096, 8192, 4096); }
  156. TEST_F(WriterTest, LargeBlockLargeBackup) {
  157. BufferWriterTest(4096, 8192, 4095);
  158. }
  159. } // namespace
  160. } // namespace internal
  161. } // namespace grpc
  162. int main(int argc, char** argv) {
  163. grpc::testing::TestEnvironment env(argc, argv);
  164. ::testing::InitGoogleTest(&argc, argv);
  165. return RUN_ALL_TESTS();
  166. }