proto_utils_test.cc
Go to the documentation of this file.
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 
19 #include <gtest/gtest.h>
20 
22 #include <grpc/slice.h>
26 
28 
29 namespace grpc {
30 
31 namespace internal {
32 
33 // Provide access to ProtoBufferWriter internals.
35  public:
37  bool have_backup() const { return writer_->have_backup_; }
38  const grpc_slice& backup_slice() const { return writer_->backup_slice_; }
39  const grpc_slice& slice() const { return writer_->slice_; }
40 
41  private:
43 };
44 
45 // Provide access to ByteBuffer internals.
47  public:
48  explicit GrpcByteBufferPeer(ByteBuffer* bb) : bb_(bb) {}
50 
51  private:
53 };
54 
56  protected:
57  static void SetUpTestCase() {
58  // Ensure the ProtoBufferWriter internals are initialized.
60  init.summon();
62  grpc_init();
63  }
64 
65  static void TearDownTestCase() { grpc_shutdown(); }
66 };
67 
68 // Regression test for a memory corruption bug where a series of
69 // ProtoBufferWriter Next()/Backup() invocations could result in a dangling
70 // pointer returned by Next() due to the interaction between grpc_slice inlining
71 // and GRPC_SLICE_START_PTR.
72 TEST_F(ProtoUtilsTest, TinyBackupThenNext) {
73  ByteBuffer bp;
74  const int block_size = 1024;
75  ProtoBufferWriter writer(&bp, block_size, 8192);
77 
78  void* data;
79  int size;
80  // Allocate a slice.
81  ASSERT_TRUE(writer.Next(&data, &size));
82  EXPECT_EQ(block_size, size);
83  // Return a single byte.
84  writer.BackUp(1);
85  EXPECT_FALSE(peer.have_backup());
86  // On the next allocation, the returned slice is non-inlined.
87  ASSERT_TRUE(writer.Next(&data, &size));
88  EXPECT_TRUE(peer.slice().refcount != nullptr);
89  EXPECT_EQ(block_size, size);
90 }
91 
92 namespace {
93 
94 // Set backup_size to 0 to indicate no backup is needed.
95 void BufferWriterTest(int block_size, int total_size, int backup_size) {
96  ByteBuffer bb;
97  ProtoBufferWriter writer(&bb, block_size, total_size);
98 
99  int written_size = 0;
100  void* data;
101  int size = 0;
102  bool backed_up_entire_slice = false;
103 
104  while (written_size < total_size) {
105  EXPECT_TRUE(writer.Next(&data, &size));
106  EXPECT_GT(size, 0);
107  EXPECT_TRUE(data);
108  int write_size = size;
109  bool should_backup = false;
110  if (backup_size > 0 && size > backup_size) {
111  write_size = size - backup_size;
112  should_backup = true;
113  } else if (size == backup_size && !backed_up_entire_slice) {
114  // only backup entire slice once.
115  backed_up_entire_slice = true;
116  should_backup = true;
117  write_size = 0;
118  }
119  // May need a last backup.
120  if (write_size + written_size > total_size) {
121  write_size = total_size - written_size;
122  should_backup = true;
123  backup_size = size - write_size;
124  ASSERT_GT(backup_size, 0);
125  }
126  for (int i = 0; i < write_size; i++) {
127  (static_cast<uint8_t*>(data))[i] = written_size % 128;
128  written_size++;
129  }
130  if (should_backup) {
131  writer.BackUp(backup_size);
132  }
133  }
134  EXPECT_EQ(bb.Length(), (size_t)total_size);
135 
137  GrpcByteBufferPeer peer(&bb);
138  grpc_byte_buffer_reader_init(&reader, peer.c_buffer());
139  int read_bytes = 0;
140  while (read_bytes < total_size) {
141  grpc_slice s;
143  for (size_t i = 0; i < GRPC_SLICE_LENGTH(s); i++) {
145  read_bytes++;
146  }
147  grpc_slice_unref(s);
148  }
149  EXPECT_EQ(read_bytes, total_size);
151 }
152 
153 class WriterTest : public ::testing::Test {
154  protected:
155  static void SetUpTestCase() {
157  init.summon();
159  // Ensure the ProtoBufferWriter internals are initialized.
160  grpc_init();
161  }
162 
163  static void TearDownTestCase() { grpc_shutdown(); }
164 };
165 
166 TEST_F(WriterTest, TinyBlockTinyBackup) {
167  for (int i = 2; i < static_cast<int> GRPC_SLICE_INLINED_SIZE; i++) {
168  BufferWriterTest(i, 256, 1);
169  }
170 }
171 
172 TEST_F(WriterTest, SmallBlockTinyBackup) { BufferWriterTest(64, 256, 1); }
173 
174 TEST_F(WriterTest, SmallBlockNoBackup) { BufferWriterTest(64, 256, 0); }
175 
176 TEST_F(WriterTest, SmallBlockFullBackup) { BufferWriterTest(64, 256, 64); }
177 
178 TEST_F(WriterTest, LargeBlockTinyBackup) { BufferWriterTest(4096, 8192, 1); }
179 
180 TEST_F(WriterTest, LargeBlockNoBackup) { BufferWriterTest(4096, 8192, 0); }
181 
182 TEST_F(WriterTest, LargeBlockFullBackup) { BufferWriterTest(4096, 8192, 4096); }
183 
184 TEST_F(WriterTest, LargeBlockLargeBackup) {
185  BufferWriterTest(4096, 8192, 4095);
186 }
187 
188 } // namespace
189 } // namespace internal
190 } // namespace grpc
191 
192 int main(int argc, char** argv) {
193  grpc::testing::TestEnvironment env(&argc, argv);
194  ::testing::InitGoogleTest(&argc, argv);
195  return RUN_ALL_TESTS();
196 }
EXPECT_FALSE
#define EXPECT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1970
grpc_slice_unref
GPRAPI void grpc_slice_unref(grpc_slice s)
Definition: slice_api.cc:32
init
const char * init
Definition: upb/upb/bindings/lua/main.c:49
grpc_slice::refcount
struct grpc_slice_refcount * refcount
Definition: include/grpc/impl/codegen/slice.h:66
grpc::ByteBuffer::c_buffer
grpc_byte_buffer * c_buffer()
Definition: include/grpcpp/impl/codegen/byte_buffer.h:201
generate.env
env
Definition: generate.py:37
grpc
Definition: grpcpp/alarm.h:33
slice.h
grpc::internal::GrpcByteBufferPeer
Definition: proto_utils_test.cc:46
EXPECT_GT
#define EXPECT_GT(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2036
grpc_byte_buffer_reader_next
GRPCAPI int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, grpc_slice *slice)
Definition: byte_buffer_reader.cc:66
absl::FormatConversionChar::s
@ s
grpc::EXPECT_TRUE
EXPECT_TRUE(status.ok())
grpc::GrpcLibraryCodegen
Classes that require gRPC to be initialized should inherit from this class.
Definition: grpcpp/impl/codegen/grpc_library.h:40
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
grpc::internal::TEST_F
TEST_F(ProtoUtilsTest, TinyBackupThenNext)
Definition: proto_utils_test.cc:72
testing::Test
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:402
grpc::internal::GrpcLibraryInitializer
Instantiating this class ensures the proper initialization of gRPC.
Definition: grpcpp/impl/grpc_library.h:39
grpc::internal::ProtoUtilsTest::SetUpTestCase
static void SetUpTestCase()
Definition: proto_utils_test.cc:57
main
int main(int argc, char **argv)
Definition: proto_utils_test.cc:192
grpc::internal::ProtoBufferWriterPeer::writer_
ProtoBufferWriter * writer_
Definition: proto_utils_test.cc:42
grpc::internal::ProtoBufferWriterPeer::ProtoBufferWriterPeer
ProtoBufferWriterPeer(ProtoBufferWriter *writer)
Definition: proto_utils_test.cc:36
grpc::internal::GrpcByteBufferPeer::GrpcByteBufferPeer
GrpcByteBufferPeer(ByteBuffer *bb)
Definition: proto_utils_test.cc:48
grpc_byte_buffer_reader_init
GRPCAPI int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, grpc_byte_buffer *buffer)
Definition: byte_buffer_reader.cc:33
grpc_byte_buffer
Definition: grpc_types.h:43
grpc::internal::ProtoBufferWriterPeer::backup_slice
const grpc_slice & backup_slice() const
Definition: proto_utils_test.cc:38
grpc::ProtoBufferWriter::have_backup_
bool have_backup_
if we are holding a backup slice or not
Definition: impl/codegen/proto_buffer_writer.h:173
GRPC_SLICE_START_PTR
#define GRPC_SLICE_START_PTR(slice)
Definition: include/grpc/impl/codegen/slice.h:101
grpc::internal::ProtoUtilsTest::TearDownTestCase
static void TearDownTestCase()
Definition: proto_utils_test.cc:65
grpc_slice
Definition: include/grpc/impl/codegen/slice.h:65
read_bytes
static int read_bytes(int fd, char *buf, size_t read_size, int spin)
Definition: low_level_ping_pong.cc:71
grpc::ByteBuffer
A sequence of bytes.
Definition: include/grpcpp/impl/codegen/byte_buffer.h:61
grpc::ProtoBufferWriter
Definition: impl/codegen/proto_buffer_writer.h:55
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
GRPC_SLICE_LENGTH
#define GRPC_SLICE_LENGTH(slice)
Definition: include/grpc/impl/codegen/slice.h:104
writer
void writer(void *n)
Definition: libuv/docs/code/locks/main.c:22
test_config.h
grpc_library.h
byte_buffer.h
grpc::ByteBuffer::Length
size_t Length() const
Buffer size in bytes.
Definition: include/grpcpp/impl/codegen/byte_buffer.h:150
grpc::ProtoBufferWriter::backup_slice_
grpc_slice backup_slice_
Definition: impl/codegen/proto_buffer_writer.h:174
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
grpc::internal::ProtoUtilsTest
Definition: proto_utils_test.cc:55
grpc_library.h
grpc::internal::GrpcByteBufferPeer::c_buffer
grpc_byte_buffer * c_buffer()
Definition: proto_utils_test.cc:49
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
proto_utils.h
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
GRPC_SLICE_INLINED_SIZE
#define GRPC_SLICE_INLINED_SIZE
Definition: include/grpc/impl/codegen/slice.h:49
grpc::EXPECT_EQ
EXPECT_EQ(grpc::StatusCode::INVALID_ARGUMENT, status.error_code())
grpc::internal::ProtoBufferWriterPeer::have_backup
bool have_backup() const
Definition: proto_utils_test.cc:37
internal
Definition: benchmark/test/output_test_helper.cc:20
grpc::internal::ProtoBufferWriterPeer::slice
const grpc_slice & slice() const
Definition: proto_utils_test.cc:39
grpc::internal::ProtoBufferWriterPeer
Definition: proto_utils_test.cc:34
grpc_init
GRPCAPI void grpc_init(void)
Definition: init.cc:146
ASSERT_GT
#define ASSERT_GT(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2076
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
grpc_byte_buffer_reader
Definition: impl/codegen/byte_buffer_reader.h:30
grpc::internal::GrpcByteBufferPeer::bb_
ByteBuffer * bb_
Definition: proto_utils_test.cc:52
grpc_shutdown
GRPCAPI void grpc_shutdown(void)
Definition: init.cc:209
reader
void reader(void *n)
Definition: libuv/docs/code/locks/main.c:8
grpc_byte_buffer_reader_destroy
GRPCAPI void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader)
Definition: byte_buffer_reader.cc:45
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
grpc::ProtoBufferWriter::slice_
grpc_slice slice_
current slice passed back to the caller
Definition: impl/codegen/proto_buffer_writer.h:176


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:47