1 //
2 //
3 // Copyright 2015 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 "src/core/lib/slice/slice.h"
20
21 #include <grpc/slice.h>
22 #include <grpc/support/alloc.h>
23 #include <grpc/support/port_platform.h>
24 #include <string.h>
25
26 #include <new>
27
28 #include "absl/log/check.h"
29 #include "src/core/lib/slice/slice_internal.h"
30 #include "src/core/lib/slice/slice_refcount.h"
31 #include "src/core/util/memory.h"
32
grpc_slice_to_c_string(grpc_slice slice)33 char* grpc_slice_to_c_string(grpc_slice slice) {
34 char* out = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1));
35 memcpy(out, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
36 out[GRPC_SLICE_LENGTH(slice)] = 0;
37 return out;
38 }
39
grpc_empty_slice(void)40 grpc_slice grpc_empty_slice(void) {
41 return grpc_core::slice_detail::EmptySlice();
42 }
43
grpc_slice_copy(grpc_slice s)44 grpc_slice grpc_slice_copy(grpc_slice s) {
45 grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s));
46 memcpy(GRPC_SLICE_START_PTR(out), GRPC_SLICE_START_PTR(s),
47 GRPC_SLICE_LENGTH(s));
48 return out;
49 }
50
51 namespace grpc_core {
52
53 // grpc_slice_new support structures - we create a refcount object extended
54 // with the user provided data pointer & destroy function
55 class NewSliceRefcount : public grpc_slice_refcount {
56 public:
NewSliceRefcount(void (* destroy)(void *),void * user_data)57 NewSliceRefcount(void (*destroy)(void*), void* user_data)
58 : grpc_slice_refcount(Destroy),
59 user_destroy_(destroy),
60 user_data_(user_data) {}
~NewSliceRefcount()61 ~NewSliceRefcount() { user_destroy_(user_data_); }
62
63 private:
Destroy(grpc_slice_refcount * arg)64 static void Destroy(grpc_slice_refcount* arg) {
65 delete static_cast<NewSliceRefcount*>(arg);
66 }
67
68 void (*user_destroy_)(void*);
69 void* user_data_;
70 };
71
72 } // namespace grpc_core
73
grpc_slice_memory_usage(grpc_slice s)74 size_t grpc_slice_memory_usage(grpc_slice s) {
75 if (s.refcount == nullptr ||
76 s.refcount == grpc_slice_refcount::NoopRefcount()) {
77 return 0;
78 } else {
79 return s.data.refcounted.length;
80 }
81 }
82
grpc_slice_from_static_buffer(const void * s,size_t len)83 grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
84 return grpc_core::StaticSlice::FromStaticBuffer(s, len).TakeCSlice();
85 }
86
grpc_slice_from_static_string(const char * s)87 grpc_slice grpc_slice_from_static_string(const char* s) {
88 return grpc_core::StaticSlice::FromStaticString(s).TakeCSlice();
89 }
90
grpc_slice_new_with_user_data(void * p,size_t len,void (* destroy)(void *),void * user_data)91 grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
92 void (*destroy)(void*),
93 void* user_data) {
94 grpc_slice slice;
95 slice.refcount = new grpc_core::NewSliceRefcount(destroy, user_data);
96 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
97 slice.data.refcounted.length = len;
98 return slice;
99 }
100
grpc_slice_new(void * p,size_t len,void (* destroy)(void *))101 grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
102 // Pass "p" to *destroy when the slice is no longer needed.
103 return grpc_slice_new_with_user_data(p, len, destroy, p);
104 }
105
106 namespace grpc_core {
107 // grpc_slice_new_with_len support structures - we create a refcount object
108 // extended with the user provided data pointer & destroy function
109 class NewWithLenSliceRefcount : public grpc_slice_refcount {
110 public:
NewWithLenSliceRefcount(void (* destroy)(void *,size_t),void * user_data,size_t user_length)111 NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
112 size_t user_length)
113 : grpc_slice_refcount(Destroy),
114 user_data_(user_data),
115 user_length_(user_length),
116 user_destroy_(destroy) {}
~NewWithLenSliceRefcount()117 ~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
118
119 private:
Destroy(grpc_slice_refcount * arg)120 static void Destroy(grpc_slice_refcount* arg) {
121 delete static_cast<NewWithLenSliceRefcount*>(arg);
122 }
123
124 void* user_data_;
125 size_t user_length_;
126 void (*user_destroy_)(void*, size_t);
127 };
128
129 /// grpc_slice_from_moved_(string|buffer) ref count .
130 class MovedStringSliceRefCount : public grpc_slice_refcount {
131 public:
MovedStringSliceRefCount(UniquePtr<char> && str)132 explicit MovedStringSliceRefCount(UniquePtr<char>&& str)
133 : grpc_slice_refcount(Destroy), str_(std::move(str)) {}
134
135 private:
Destroy(grpc_slice_refcount * arg)136 static void Destroy(grpc_slice_refcount* arg) {
137 delete static_cast<MovedStringSliceRefCount*>(arg);
138 }
139
140 UniquePtr<char> str_;
141 };
142
143 // grpc_slice_from_cpp_string() ref count.
144 class MovedCppStringSliceRefCount : public grpc_slice_refcount {
145 public:
MovedCppStringSliceRefCount(std::string && str)146 explicit MovedCppStringSliceRefCount(std::string&& str)
147 : grpc_slice_refcount(Destroy), str_(std::move(str)) {}
148
data()149 uint8_t* data() {
150 return reinterpret_cast<uint8_t*>(const_cast<char*>(str_.data()));
151 }
152
size() const153 size_t size() const { return str_.size(); }
154
155 private:
Destroy(grpc_slice_refcount * arg)156 static void Destroy(grpc_slice_refcount* arg) {
157 delete static_cast<MovedCppStringSliceRefCount*>(arg);
158 }
159
160 std::string str_;
161 };
162
163 } // namespace grpc_core
164
grpc_slice_new_with_len(void * p,size_t len,void (* destroy)(void *,size_t))165 grpc_slice grpc_slice_new_with_len(void* p, size_t len,
166 void (*destroy)(void*, size_t)) {
167 grpc_slice slice;
168 slice.refcount = new grpc_core::NewWithLenSliceRefcount(destroy, p, len);
169 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
170 slice.data.refcounted.length = len;
171 return slice;
172 }
173
grpc_slice_from_copied_buffer(const char * source,size_t len)174 grpc_slice grpc_slice_from_copied_buffer(const char* source, size_t len) {
175 if (len == 0) return grpc_empty_slice();
176 grpc_slice out = grpc_slice_malloc(len);
177 memcpy(GRPC_SLICE_START_PTR(out), source, len);
178 return out;
179 }
180
grpc_slice_from_copied_string(const char * source)181 grpc_slice grpc_slice_from_copied_string(const char* source) {
182 return grpc_slice_from_copied_buffer(source, strlen(source));
183 }
184
grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,size_t len)185 grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
186 size_t len) {
187 uint8_t* ptr = reinterpret_cast<uint8_t*>(p.get());
188 grpc_slice slice;
189 if (len <= sizeof(slice.data.inlined.bytes)) {
190 slice.refcount = nullptr;
191 slice.data.inlined.length = len;
192 memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
193 } else {
194 slice.refcount = new grpc_core::MovedStringSliceRefCount(std::move(p));
195 slice.data.refcounted.bytes = ptr;
196 slice.data.refcounted.length = len;
197 }
198 return slice;
199 }
200
grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p)201 grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p) {
202 const size_t len = strlen(p.get());
203 return grpc_slice_from_moved_buffer(std::move(p), len);
204 }
205
grpc_slice_from_cpp_string(std::string str)206 grpc_slice grpc_slice_from_cpp_string(std::string str) {
207 grpc_slice slice;
208 if (str.size() <= sizeof(slice.data.inlined.bytes)) {
209 slice.refcount = nullptr;
210 slice.data.inlined.length = str.size();
211 memcpy(GRPC_SLICE_START_PTR(slice), str.data(), str.size());
212 } else {
213 auto* refcount = new grpc_core::MovedCppStringSliceRefCount(std::move(str));
214 slice.data.refcounted.bytes = refcount->data();
215 slice.data.refcounted.length = refcount->size();
216 slice.refcount = refcount;
217 }
218 return slice;
219 }
220
grpc_slice_malloc_large(size_t length)221 grpc_slice grpc_slice_malloc_large(size_t length) {
222 grpc_slice slice;
223 uint8_t* memory = new uint8_t[sizeof(grpc_slice_refcount) + length];
224 slice.refcount = new (memory) grpc_slice_refcount(
225 [](grpc_slice_refcount* p) { delete[] reinterpret_cast<uint8_t*>(p); });
226 slice.data.refcounted.bytes = memory + sizeof(grpc_slice_refcount);
227 slice.data.refcounted.length = length;
228 return slice;
229 }
230
grpc_slice_malloc(size_t length)231 grpc_slice grpc_slice_malloc(size_t length) {
232 if (length <= GRPC_SLICE_INLINED_SIZE) {
233 grpc_slice slice;
234 slice.refcount = nullptr;
235 slice.data.inlined.length = length;
236 return slice;
237 } else {
238 return grpc_slice_malloc_large(length);
239 }
240 }
241
sub_no_ref(const grpc_slice & source,size_t begin,size_t end)242 static grpc_slice sub_no_ref(const grpc_slice& source, size_t begin,
243 size_t end) {
244 grpc_slice subset;
245
246 CHECK(end >= begin);
247
248 if (source.refcount != nullptr) {
249 // Enforce preconditions
250 CHECK(source.data.refcounted.length >= end);
251
252 // Build the result
253 subset.refcount = source.refcount;
254 // Point into the source array
255 subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
256 subset.data.refcounted.length = end - begin;
257 } else {
258 // Enforce preconditions
259 CHECK(source.data.inlined.length >= end);
260 subset.refcount = nullptr;
261 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
262 memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
263 end - begin);
264 }
265 return subset;
266 }
267
grpc_slice_sub_no_ref(grpc_slice source,size_t begin,size_t end)268 grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
269 return sub_no_ref(source, begin, end);
270 }
271
grpc_slice_sub(grpc_slice source,size_t begin,size_t end)272 grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
273 grpc_slice subset;
274
275 if (end - begin <= sizeof(subset.data.inlined.bytes)) {
276 subset.refcount = nullptr;
277 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
278 memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
279 end - begin);
280 } else {
281 subset = grpc_slice_sub_no_ref(source, begin, end);
282 // Bump the refcount
283 if (subset.refcount != grpc_slice_refcount::NoopRefcount()) {
284 subset.refcount->Ref({});
285 }
286 }
287 return subset;
288 }
289
290 template <bool allow_inline>
grpc_slice_split_tail_maybe_ref_impl(grpc_slice * source,size_t split,grpc_slice_ref_whom ref_whom)291 grpc_slice grpc_slice_split_tail_maybe_ref_impl(grpc_slice* source,
292 size_t split,
293 grpc_slice_ref_whom ref_whom) {
294 grpc_slice tail;
295
296 if (source->refcount == nullptr) {
297 // inlined data, copy it out
298 CHECK(source->data.inlined.length >= split);
299 tail.refcount = nullptr;
300 tail.data.inlined.length =
301 static_cast<uint8_t>(source->data.inlined.length - split);
302 memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
303 tail.data.inlined.length);
304 source->data.inlined.length = static_cast<uint8_t>(split);
305 } else if (source->refcount == grpc_slice_refcount::NoopRefcount()) {
306 // refcount == NoopRefcount(), so we can just split in-place
307 tail.refcount = grpc_slice_refcount::NoopRefcount();
308 tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
309 tail.data.refcounted.length = source->data.refcounted.length - split;
310 source->data.refcounted.length = split;
311 } else {
312 size_t tail_length = source->data.refcounted.length - split;
313 CHECK(source->data.refcounted.length >= split);
314 if (allow_inline && tail_length < sizeof(tail.data.inlined.bytes) &&
315 ref_whom != GRPC_SLICE_REF_TAIL) {
316 // Copy out the bytes - it'll be cheaper than refcounting
317 tail.refcount = nullptr;
318 tail.data.inlined.length = static_cast<uint8_t>(tail_length);
319 memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
320 tail_length);
321 } else {
322 // Build the result
323 switch (ref_whom) {
324 case GRPC_SLICE_REF_TAIL:
325 tail.refcount = source->refcount;
326 source->refcount = grpc_slice_refcount::NoopRefcount();
327 break;
328 case GRPC_SLICE_REF_HEAD:
329 tail.refcount = grpc_slice_refcount::NoopRefcount();
330 break;
331 case GRPC_SLICE_REF_BOTH:
332 tail.refcount = source->refcount;
333 // Bump the refcount
334 if (tail.refcount != grpc_slice_refcount::NoopRefcount()) {
335 tail.refcount->Ref({});
336 }
337 break;
338 }
339 // Point into the source array
340 tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
341 tail.data.refcounted.length = tail_length;
342 }
343 source->data.refcounted.length = split;
344 }
345
346 return tail;
347 }
348
grpc_slice_split_tail_maybe_ref(grpc_slice * source,size_t split,grpc_slice_ref_whom ref_whom)349 grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
350 grpc_slice_ref_whom ref_whom) {
351 return grpc_slice_split_tail_maybe_ref_impl<true>(source, split, ref_whom);
352 }
353
grpc_slice_split_tail_maybe_ref_no_inline(grpc_slice * source,size_t split,grpc_slice_ref_whom ref_whom)354 grpc_slice grpc_slice_split_tail_maybe_ref_no_inline(
355 grpc_slice* source, size_t split, grpc_slice_ref_whom ref_whom) {
356 return grpc_slice_split_tail_maybe_ref_impl<false>(source, split, ref_whom);
357 }
358
grpc_slice_split_tail(grpc_slice * source,size_t split)359 grpc_slice grpc_slice_split_tail(grpc_slice* source, size_t split) {
360 return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH);
361 }
362
grpc_slice_split_tail_no_inline(grpc_slice * source,size_t split)363 grpc_slice grpc_slice_split_tail_no_inline(grpc_slice* source, size_t split) {
364 return grpc_slice_split_tail_maybe_ref_no_inline(source, split,
365 GRPC_SLICE_REF_BOTH);
366 }
367
368 template <bool allow_inline>
grpc_slice_split_head_impl(grpc_slice * source,size_t split)369 grpc_slice grpc_slice_split_head_impl(grpc_slice* source, size_t split) {
370 grpc_slice head;
371
372 if (source->refcount == nullptr) {
373 CHECK(source->data.inlined.length >= split);
374
375 head.refcount = nullptr;
376 head.data.inlined.length = static_cast<uint8_t>(split);
377 memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
378 source->data.inlined.length =
379 static_cast<uint8_t>(source->data.inlined.length - split);
380 memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
381 source->data.inlined.length);
382 } else if (allow_inline && split < sizeof(head.data.inlined.bytes)) {
383 CHECK(source->data.refcounted.length >= split);
384
385 head.refcount = nullptr;
386 head.data.inlined.length = static_cast<uint8_t>(split);
387 memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
388 source->data.refcounted.bytes += split;
389 source->data.refcounted.length -= split;
390 } else {
391 CHECK(source->data.refcounted.length >= split);
392
393 // Build the result
394 head.refcount = source->refcount;
395 // Bump the refcount
396 if (head.refcount != grpc_slice_refcount::NoopRefcount()) {
397 head.refcount->Ref({});
398 }
399 // Point into the source array
400 head.data.refcounted.bytes = source->data.refcounted.bytes;
401 head.data.refcounted.length = split;
402 source->data.refcounted.bytes += split;
403 source->data.refcounted.length -= split;
404 }
405
406 return head;
407 }
408
grpc_slice_split_head(grpc_slice * source,size_t split)409 grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
410 return grpc_slice_split_head_impl<true>(source, split);
411 }
412
grpc_slice_split_head_no_inline(grpc_slice * source,size_t split)413 grpc_slice grpc_slice_split_head_no_inline(grpc_slice* source, size_t split) {
414 return grpc_slice_split_head_impl<false>(source, split);
415 }
416
grpc_slice_eq(grpc_slice a,grpc_slice b)417 int grpc_slice_eq(grpc_slice a, grpc_slice b) {
418 if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
419 if (GRPC_SLICE_LENGTH(a) == 0) return true;
420 return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
421 GRPC_SLICE_LENGTH(a));
422 }
423
grpc_slice_differs_refcounted(const grpc_slice & a,const grpc_slice & b_not_inline)424 int grpc_slice_differs_refcounted(const grpc_slice& a,
425 const grpc_slice& b_not_inline) {
426 size_t a_len;
427 const uint8_t* a_ptr;
428 if (a.refcount) {
429 a_len = a.data.refcounted.length;
430 a_ptr = a.data.refcounted.bytes;
431 } else {
432 a_len = a.data.inlined.length;
433 a_ptr = &a.data.inlined.bytes[0];
434 }
435 if (a_len != b_not_inline.data.refcounted.length) {
436 return true;
437 }
438 if (a_len == 0) {
439 return false;
440 }
441 // This check *must* occur after the a_len == 0 check
442 // to retain compatibility with grpc_slice_eq.
443 if (a_ptr == nullptr) {
444 return true;
445 }
446 return memcmp(a_ptr, b_not_inline.data.refcounted.bytes, a_len);
447 }
448
grpc_slice_cmp(grpc_slice a,grpc_slice b)449 int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
450 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
451 if (d != 0) return d;
452 return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
453 GRPC_SLICE_LENGTH(a));
454 }
455
grpc_slice_str_cmp(grpc_slice a,const char * b)456 int grpc_slice_str_cmp(grpc_slice a, const char* b) {
457 size_t b_length = strlen(b);
458 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - b_length);
459 if (d != 0) return d;
460 return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
461 }
462
grpc_slice_is_equivalent(grpc_slice a,grpc_slice b)463 int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
464 if (a.refcount == nullptr || b.refcount == nullptr) {
465 return grpc_slice_eq(a, b);
466 }
467 return a.data.refcounted.length == b.data.refcounted.length &&
468 a.data.refcounted.bytes == b.data.refcounted.bytes;
469 }
470
grpc_slice_buf_start_eq(grpc_slice a,const void * b,size_t len)471 int grpc_slice_buf_start_eq(grpc_slice a, const void* b, size_t len) {
472 if (GRPC_SLICE_LENGTH(a) < len) return 0;
473 return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len);
474 }
475
grpc_slice_rchr(grpc_slice s,char c)476 int grpc_slice_rchr(grpc_slice s, char c) {
477 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
478 int i;
479 for (i = static_cast<int> GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c;
480 i--) {
481 }
482 return i;
483 }
484
grpc_slice_chr(grpc_slice s,char c)485 int grpc_slice_chr(grpc_slice s, char c) {
486 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
487 const char* p = static_cast<const char*>(memchr(b, c, GRPC_SLICE_LENGTH(s)));
488 return p == nullptr ? -1 : static_cast<int>(p - b);
489 }
490
grpc_slice_slice(grpc_slice haystack,grpc_slice needle)491 int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
492 size_t haystack_len = GRPC_SLICE_LENGTH(haystack);
493 const uint8_t* haystack_bytes = GRPC_SLICE_START_PTR(haystack);
494 size_t needle_len = GRPC_SLICE_LENGTH(needle);
495 const uint8_t* needle_bytes = GRPC_SLICE_START_PTR(needle);
496
497 if (haystack_len == 0 || needle_len == 0) return -1;
498 if (haystack_len < needle_len) return -1;
499 if (haystack_len == needle_len) {
500 return grpc_slice_eq(haystack, needle) ? 0 : -1;
501 }
502 if (needle_len == 1) {
503 return grpc_slice_chr(haystack, static_cast<char>(*needle_bytes));
504 }
505
506 const uint8_t* last = haystack_bytes + haystack_len - needle_len;
507 for (const uint8_t* cur = haystack_bytes; cur <= last; ++cur) {
508 if (0 == memcmp(cur, needle_bytes, needle_len)) {
509 return static_cast<int>(cur - haystack_bytes);
510 }
511 }
512 return -1;
513 }
514
grpc_slice_dup(grpc_slice a)515 grpc_slice grpc_slice_dup(grpc_slice a) {
516 grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a));
517 memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a),
518 GRPC_SLICE_LENGTH(a));
519 return copy;
520 }
521
grpc_slice_ref(grpc_slice slice)522 grpc_slice grpc_slice_ref(grpc_slice slice) {
523 return grpc_core::CSliceRef(slice);
524 }
525
grpc_slice_unref(grpc_slice slice)526 void grpc_slice_unref(grpc_slice slice) { grpc_core::CSliceUnref(slice); }
527