Coverage Report

Created: 2025-06-11 06:40

/src/boringssl/crypto/mem_internal.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2025 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef OPENSSL_HEADER_CRYPTO_MEM_INTERNAL_H
16
#define OPENSSL_HEADER_CRYPTO_MEM_INTERNAL_H
17
18
#include <openssl/mem.h>
19
20
#include <algorithm>
21
#include <memory>
22
#include <type_traits>
23
#include <utility>
24
25
#include <openssl/err.h>
26
#include <openssl/span.h>
27
28
29
BSSL_NAMESPACE_BEGIN
30
31
// Internal allocation-dependent functions.
32
//
33
// This header is separate from crypto/internal.h because there are some files
34
// which must avoid |OPENSSL_malloc|, to avoid a circular dependency, but
35
// need other support routines in crypto/internal.h. (See
36
// |_BORINGSSL_PROHIBIT_OPENSSL_MALLOC|.)
37
38
39
// Memory allocation.
40
41
// New behaves like |new| but uses |OPENSSL_malloc| for memory allocation. It
42
// returns nullptr on allocation error. It only implements single-object
43
// allocation and not new T[n].
44
//
45
// Note: unlike |new|, this does not support non-public constructors.
46
template <typename T, typename... Args>
47
6
T *New(Args &&...args) {
48
6
  void *t = OPENSSL_malloc(sizeof(T));
49
6
  if (t == nullptr) {
50
0
    return nullptr;
51
0
  }
52
6
  return new (t) T(std::forward<Args>(args)...);
53
6
}
Unexecuted instantiation: evp_pkey_ctx_st* bssl::New<evp_pkey_ctx_st>()
bignum_ctx* bssl::New<bignum_ctx>()
Line
Count
Source
47
6
T *New(Args &&...args) {
48
6
  void *t = OPENSSL_malloc(sizeof(T));
49
6
  if (t == nullptr) {
50
0
    return nullptr;
51
0
  }
52
6
  return new (t) T(std::forward<Args>(args)...);
53
6
}
54
55
// Delete behaves like |delete| but uses |OPENSSL_free| to release memory.
56
//
57
// Note: unlike |delete| this does not support non-public destructors.
58
template <typename T>
59
6
void Delete(T *t) {
60
6
  if (t != nullptr) {
61
6
    t->~T();
62
6
    OPENSSL_free(t);
63
6
  }
64
6
}
Unexecuted instantiation: void bssl::Delete<evp_pkey_ctx_st>(evp_pkey_ctx_st*)
void bssl::Delete<bignum_ctx>(bignum_ctx*)
Line
Count
Source
59
6
void Delete(T *t) {
60
6
  if (t != nullptr) {
61
6
    t->~T();
62
6
    OPENSSL_free(t);
63
6
  }
64
6
}
65
66
// All types with kAllowUniquePtr set may be used with UniquePtr. Other types
67
// may be C structs which require a |BORINGSSL_MAKE_DELETER| registration.
68
namespace internal {
69
template <typename T>
70
struct DeleterImpl<T, std::enable_if_t<T::kAllowUniquePtr>> {
71
  static void Free(T *t) { Delete(t); }
72
};
73
}  // namespace internal
74
75
// MakeUnique behaves like |std::make_unique| but returns nullptr on allocation
76
// error.
77
template <typename T, typename... Args>
78
0
UniquePtr<T> MakeUnique(Args &&...args) {
79
0
  return UniquePtr<T>(New<T>(std::forward<Args>(args)...));
80
0
}
81
82
83
// Containers.
84
85
// Array<T> is an owning array of elements of |T|.
86
template <typename T>
87
class Array {
88
 public:
89
  // Array's default constructor creates an empty array.
90
  Array() {}
91
  Array(const Array &) = delete;
92
  Array(Array &&other) { *this = std::move(other); }
93
94
  ~Array() { Reset(); }
95
96
  Array &operator=(const Array &) = delete;
97
  Array &operator=(Array &&other) {
98
    Reset();
99
    other.Release(&data_, &size_);
100
    return *this;
101
  }
102
103
  const T *data() const { return data_; }
104
  T *data() { return data_; }
105
  size_t size() const { return size_; }
106
  bool empty() const { return size_ == 0; }
107
108
  const T &operator[](size_t i) const {
109
    BSSL_CHECK(i < size_);
110
    return data_[i];
111
  }
112
  T &operator[](size_t i) {
113
    BSSL_CHECK(i < size_);
114
    return data_[i];
115
  }
116
117
  T &front() {
118
    BSSL_CHECK(size_ != 0);
119
    return data_[0];
120
  }
121
  const T &front() const {
122
    BSSL_CHECK(size_ != 0);
123
    return data_[0];
124
  }
125
  T &back() {
126
    BSSL_CHECK(size_ != 0);
127
    return data_[size_ - 1];
128
  }
129
  const T &back() const {
130
    BSSL_CHECK(size_ != 0);
131
    return data_[size_ - 1];
132
  }
133
134
  T *begin() { return data_; }
135
  const T *begin() const { return data_; }
136
  T *end() { return data_ + size_; }
137
  const T *end() const { return data_ + size_; }
138
139
  void Reset() { Reset(nullptr, 0); }
140
141
  // Reset releases the current contents of the array and takes ownership of the
142
  // raw pointer supplied by the caller.
143
  void Reset(T *new_data, size_t new_size) {
144
    std::destroy_n(data_, size_);
145
    OPENSSL_free(data_);
146
    data_ = new_data;
147
    size_ = new_size;
148
  }
149
150
  // Release releases ownership of the array to a raw pointer supplied by the
151
  // caller.
152
  void Release(T **out, size_t *out_size) {
153
    *out = data_;
154
    *out_size = size_;
155
    data_ = nullptr;
156
    size_ = 0;
157
  }
158
159
  // Init replaces the array with a newly-allocated array of |new_size|
160
  // value-constructed copies of |T|. It returns true on success and false on
161
  // error. If |T| is a primitive type like |uint8_t|, value-construction means
162
  // it will be zero-initialized.
163
  [[nodiscard]] bool Init(size_t new_size) {
164
    if (!InitUninitialized(new_size)) {
165
      return false;
166
    }
167
    std::uninitialized_value_construct_n(data_, size_);
168
    return true;
169
  }
170
171
  // InitForOverwrite behaves like |Init| but it default-constructs each element
172
  // instead. This means that, if |T| is a primitive type, the array will be
173
  // uninitialized and thus must be filled in by the caller.
174
  [[nodiscard]] bool InitForOverwrite(size_t new_size) {
175
    if (!InitUninitialized(new_size)) {
176
      return false;
177
    }
178
    std::uninitialized_default_construct_n(data_, size_);
179
    return true;
180
  }
181
182
  // CopyFrom replaces the array with a newly-allocated copy of |in|. It returns
183
  // true on success and false on error.
184
  [[nodiscard]] bool CopyFrom(Span<const T> in) {
185
    if (!InitUninitialized(in.size())) {
186
      return false;
187
    }
188
    std::uninitialized_copy(in.begin(), in.end(), data_);
189
    return true;
190
  }
191
192
  // Shrink shrinks the stored size of the array to |new_size|. It crashes if
193
  // the new size is larger. Note this does not shrink the allocation itself.
194
  void Shrink(size_t new_size) {
195
    if (new_size > size_) {
196
      abort();
197
    }
198
    std::destroy_n(data_ + new_size, size_ - new_size);
199
    size_ = new_size;
200
  }
201
202
 private:
203
  // InitUninitialized replaces the array with a newly-allocated array of
204
  // |new_size| elements, but whose constructor has not yet run. On success, the
205
  // elements must be constructed before returning control to the caller.
206
  bool InitUninitialized(size_t new_size) {
207
    Reset();
208
    if (new_size == 0) {
209
      return true;
210
    }
211
212
    if (new_size > SIZE_MAX / sizeof(T)) {
213
      OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
214
      return false;
215
    }
216
    data_ = reinterpret_cast<T *>(OPENSSL_malloc(new_size * sizeof(T)));
217
    if (data_ == nullptr) {
218
      return false;
219
    }
220
    size_ = new_size;
221
    return true;
222
  }
223
224
  T *data_ = nullptr;
225
  size_t size_ = 0;
226
};
227
228
// Vector<T> is a resizable array of elements of |T|.
229
template <typename T>
230
class Vector {
231
 public:
232
12
  Vector() = default;
bssl::Vector<std::__1::unique_ptr<bignum_st, bssl::internal::Deleter> >::Vector()
Line
Count
Source
232
6
  Vector() = default;
bssl::Vector<unsigned long>::Vector()
Line
Count
Source
232
6
  Vector() = default;
233
  Vector(const Vector &) = delete;
234
  Vector(Vector &&other) { *this = std::move(other); }
235
12
  ~Vector() { clear(); }
bssl::Vector<unsigned long>::~Vector()
Line
Count
Source
235
6
  ~Vector() { clear(); }
bssl::Vector<std::__1::unique_ptr<bignum_st, bssl::internal::Deleter> >::~Vector()
Line
Count
Source
235
6
  ~Vector() { clear(); }
236
237
  Vector &operator=(const Vector &) = delete;
238
  Vector &operator=(Vector &&other) {
239
    clear();
240
    std::swap(data_, other.data_);
241
    std::swap(size_, other.size_);
242
    std::swap(capacity_, other.capacity_);
243
    return *this;
244
  }
245
246
  const T *data() const { return data_; }
247
  T *data() { return data_; }
248
102
  size_t size() const { return size_; }
249
78
  bool empty() const { return size_ == 0; }
250
251
  const T &operator[](size_t i) const {
252
    BSSL_CHECK(i < size_);
253
    return data_[i];
254
  }
255
102
  T &operator[](size_t i) {
256
102
    BSSL_CHECK(i < size_);
257
102
    return data_[i];
258
102
  }
259
260
  T &front() {
261
    BSSL_CHECK(size_ != 0);
262
    return data_[0];
263
  }
264
  const T &front() const {
265
    BSSL_CHECK(size_ != 0);
266
    return data_[0];
267
  }
268
78
  T &back() {
269
78
    BSSL_CHECK(size_ != 0);
270
78
    return data_[size_ - 1];
271
78
  }
272
  const T &back() const {
273
    BSSL_CHECK(size_ != 0);
274
    return data_[size_ - 1];
275
  }
276
277
12
  T *begin() { return data_; }
bssl::Vector<unsigned long>::begin()
Line
Count
Source
277
6
  T *begin() { return data_; }
bssl::Vector<std::__1::unique_ptr<bignum_st, bssl::internal::Deleter> >::begin()
Line
Count
Source
277
6
  T *begin() { return data_; }
278
  const T *begin() const { return data_; }
279
12
  T *end() { return data_ + size_; }
bssl::Vector<unsigned long>::end()
Line
Count
Source
279
6
  T *end() { return data_ + size_; }
bssl::Vector<std::__1::unique_ptr<bignum_st, bssl::internal::Deleter> >::end()
Line
Count
Source
279
6
  T *end() { return data_ + size_; }
280
  const T *end() const { return data_ + size_; }
281
282
24
  void clear() {
283
24
    std::destroy_n(data_, size_);
284
24
    OPENSSL_free(data_);
285
24
    data_ = nullptr;
286
24
    size_ = 0;
287
24
    capacity_ = 0;
288
24
  }
bssl::Vector<unsigned long>::clear()
Line
Count
Source
282
12
  void clear() {
283
12
    std::destroy_n(data_, size_);
284
12
    OPENSSL_free(data_);
285
12
    data_ = nullptr;
286
12
    size_ = 0;
287
12
    capacity_ = 0;
288
12
  }
bssl::Vector<std::__1::unique_ptr<bignum_st, bssl::internal::Deleter> >::clear()
Line
Count
Source
282
12
  void clear() {
283
12
    std::destroy_n(data_, size_);
284
12
    OPENSSL_free(data_);
285
12
    data_ = nullptr;
286
12
    size_ = 0;
287
12
    capacity_ = 0;
288
12
  }
289
290
78
  void pop_back() {
291
78
    BSSL_CHECK(size_ != 0);
292
78
    std::destroy_at(&data_[size_ - 1]);
293
78
    size_--;
294
78
  }
295
296
  // Push adds |elem| at the end of the internal array, growing if necessary. It
297
  // returns false when allocation fails.
298
102
  [[nodiscard]] bool Push(T elem) {
299
102
    if (!MaybeGrow()) {
300
0
      return false;
301
0
    }
302
102
    new (&data_[size_]) T(std::move(elem));
303
102
    size_++;
304
102
    return true;
305
102
  }
bssl::Vector<unsigned long>::Push(unsigned long)
Line
Count
Source
298
78
  [[nodiscard]] bool Push(T elem) {
299
78
    if (!MaybeGrow()) {
300
0
      return false;
301
0
    }
302
78
    new (&data_[size_]) T(std::move(elem));
303
78
    size_++;
304
78
    return true;
305
78
  }
bssl::Vector<std::__1::unique_ptr<bignum_st, bssl::internal::Deleter> >::Push(std::__1::unique_ptr<bignum_st, bssl::internal::Deleter>)
Line
Count
Source
298
24
  [[nodiscard]] bool Push(T elem) {
299
24
    if (!MaybeGrow()) {
300
0
      return false;
301
0
    }
302
24
    new (&data_[size_]) T(std::move(elem));
303
24
    size_++;
304
24
    return true;
305
24
  }
306
307
  // CopyFrom replaces the contents of the array with a copy of |in|. It returns
308
  // true on success and false on allocation error.
309
  [[nodiscard]] bool CopyFrom(Span<const T> in) {
310
    Array<T> copy;
311
    if (!copy.CopyFrom(in)) {
312
      return false;
313
    }
314
315
    clear();
316
    copy.Release(&data_, &size_);
317
    capacity_ = size_;
318
    return true;
319
  }
320
321
 private:
322
  // If there is no room for one more element, creates a new backing array with
323
  // double the size of the old one and copies elements over.
324
102
  bool MaybeGrow() {
325
    // No need to grow if we have room for one more T.
326
102
    if (size_ < capacity_) {
327
90
      return true;
328
90
    }
329
12
    size_t new_capacity = kDefaultSize;
330
12
    if (capacity_ > 0) {
331
      // Double the array's size if it's safe to do so.
332
0
      if (capacity_ > SIZE_MAX / 2) {
333
0
        OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
334
0
        return false;
335
0
      }
336
0
      new_capacity = capacity_ * 2;
337
0
    }
338
12
    if (new_capacity > SIZE_MAX / sizeof(T)) {
339
0
      OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
340
0
      return false;
341
0
    }
342
12
    T *new_data =
343
12
        reinterpret_cast<T *>(OPENSSL_malloc(new_capacity * sizeof(T)));
344
12
    if (new_data == nullptr) {
345
0
      return false;
346
0
    }
347
12
    size_t new_size = size_;
348
12
    std::uninitialized_move(begin(), end(), new_data);
349
12
    clear();
350
12
    data_ = new_data;
351
12
    size_ = new_size;
352
12
    capacity_ = new_capacity;
353
12
    return true;
354
12
  }
bssl::Vector<unsigned long>::MaybeGrow()
Line
Count
Source
324
78
  bool MaybeGrow() {
325
    // No need to grow if we have room for one more T.
326
78
    if (size_ < capacity_) {
327
72
      return true;
328
72
    }
329
6
    size_t new_capacity = kDefaultSize;
330
6
    if (capacity_ > 0) {
331
      // Double the array's size if it's safe to do so.
332
0
      if (capacity_ > SIZE_MAX / 2) {
333
0
        OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
334
0
        return false;
335
0
      }
336
0
      new_capacity = capacity_ * 2;
337
0
    }
338
6
    if (new_capacity > SIZE_MAX / sizeof(T)) {
339
0
      OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
340
0
      return false;
341
0
    }
342
6
    T *new_data =
343
6
        reinterpret_cast<T *>(OPENSSL_malloc(new_capacity * sizeof(T)));
344
6
    if (new_data == nullptr) {
345
0
      return false;
346
0
    }
347
6
    size_t new_size = size_;
348
6
    std::uninitialized_move(begin(), end(), new_data);
349
6
    clear();
350
6
    data_ = new_data;
351
6
    size_ = new_size;
352
6
    capacity_ = new_capacity;
353
6
    return true;
354
6
  }
bssl::Vector<std::__1::unique_ptr<bignum_st, bssl::internal::Deleter> >::MaybeGrow()
Line
Count
Source
324
24
  bool MaybeGrow() {
325
    // No need to grow if we have room for one more T.
326
24
    if (size_ < capacity_) {
327
18
      return true;
328
18
    }
329
6
    size_t new_capacity = kDefaultSize;
330
6
    if (capacity_ > 0) {
331
      // Double the array's size if it's safe to do so.
332
0
      if (capacity_ > SIZE_MAX / 2) {
333
0
        OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
334
0
        return false;
335
0
      }
336
0
      new_capacity = capacity_ * 2;
337
0
    }
338
6
    if (new_capacity > SIZE_MAX / sizeof(T)) {
339
0
      OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
340
0
      return false;
341
0
    }
342
6
    T *new_data =
343
6
        reinterpret_cast<T *>(OPENSSL_malloc(new_capacity * sizeof(T)));
344
6
    if (new_data == nullptr) {
345
0
      return false;
346
0
    }
347
6
    size_t new_size = size_;
348
6
    std::uninitialized_move(begin(), end(), new_data);
349
6
    clear();
350
6
    data_ = new_data;
351
6
    size_ = new_size;
352
6
    capacity_ = new_capacity;
353
6
    return true;
354
6
  }
355
356
  // data_ is a pointer to |capacity_| objects of size |T|, the first |size_| of
357
  // which are constructed.
358
  T *data_ = nullptr;
359
  // |size_| is the number of elements stored in this Vector.
360
  size_t size_ = 0;
361
  // |capacity_| is the number of elements allocated in this Vector.
362
  size_t capacity_ = 0;
363
  // |kDefaultSize| is the default initial size of the backing array.
364
  static constexpr size_t kDefaultSize = 16;
365
};
366
367
// A PackedSize is an integer that can store values from 0 to N, represented as
368
// a minimal-width integer.
369
template <size_t N>
370
using PackedSize = std::conditional_t<
371
    N <= 0xff, uint8_t,
372
    std::conditional_t<N <= 0xffff, uint16_t,
373
                       std::conditional_t<N <= 0xffffffff, uint32_t, size_t>>>;
374
375
// An InplaceVector is like a Vector, but stores up to N elements inline in the
376
// object. It is inspired by std::inplace_vector in C++26.
377
template <typename T, size_t N>
378
class InplaceVector {
379
 public:
380
  InplaceVector() = default;
381
  InplaceVector(const InplaceVector &other) { *this = other; }
382
  InplaceVector(InplaceVector &&other) { *this = std::move(other); }
383
  ~InplaceVector() { clear(); }
384
  InplaceVector &operator=(const InplaceVector &other) {
385
    if (this != &other) {
386
      CopyFrom(other);
387
    }
388
    return *this;
389
  }
390
  InplaceVector &operator=(InplaceVector &&other) {
391
    clear();
392
    std::uninitialized_move(other.begin(), other.end(), data());
393
    size_ = other.size();
394
    return *this;
395
  }
396
397
  const T *data() const { return reinterpret_cast<const T *>(storage_); }
398
  T *data() { return reinterpret_cast<T *>(storage_); }
399
  size_t size() const { return size_; }
400
  static constexpr size_t capacity() { return N; }
401
  bool empty() const { return size_ == 0; }
402
403
  const T &operator[](size_t i) const {
404
    BSSL_CHECK(i < size_);
405
    return data()[i];
406
  }
407
  T &operator[](size_t i) {
408
    BSSL_CHECK(i < size_);
409
    return data()[i];
410
  }
411
412
  T &front() {
413
    BSSL_CHECK(size_ != 0);
414
    return data()[0];
415
  }
416
  const T &front() const {
417
    BSSL_CHECK(size_ != 0);
418
    return data()[0];
419
  }
420
  T &back() {
421
    BSSL_CHECK(size_ != 0);
422
    return data()[size_ - 1];
423
  }
424
  const T &back() const {
425
    BSSL_CHECK(size_ != 0);
426
    return data()[size_ - 1];
427
  }
428
429
  T *begin() { return data(); }
430
  const T *begin() const { return data(); }
431
  T *end() { return data() + size_; }
432
  const T *end() const { return data() + size_; }
433
434
  void clear() { Shrink(0); }
435
436
  void pop_back() {
437
    BSSL_CHECK(size_ != 0);
438
    Shrink(size_ - 1);
439
  }
440
441
  // Shrink resizes the vector to |new_size|, which must not be larger than the
442
  // current size. Unlike |Resize|, this can be called when |T| is not
443
  // default-constructible.
444
  void Shrink(size_t new_size) {
445
    BSSL_CHECK(new_size <= size_);
446
    std::destroy_n(data() + new_size, size_ - new_size);
447
    size_ = static_cast<PackedSize<N>>(new_size);
448
  }
449
450
  // TryResize resizes the vector to |new_size| and returns true, or returns
451
  // false if |new_size| is too large. Any newly-added elements are
452
  // value-initialized.
453
  [[nodiscard]] bool TryResize(size_t new_size) {
454
    if (new_size <= size_) {
455
      Shrink(new_size);
456
      return true;
457
    }
458
    if (new_size > capacity()) {
459
      return false;
460
    }
461
    std::uninitialized_value_construct_n(data() + size_, new_size - size_);
462
    size_ = static_cast<PackedSize<N>>(new_size);
463
    return true;
464
  }
465
466
  // TryResizeForOverwrite behaves like |TryResize|, but newly-added elements
467
  // are default-initialized, so POD types may contain uninitialized values that
468
  // the caller is responsible for filling in.
469
  [[nodiscard]] bool TryResizeForOverwrite(size_t new_size) {
470
    if (new_size <= size_) {
471
      Shrink(new_size);
472
      return true;
473
    }
474
    if (new_size > capacity()) {
475
      return false;
476
    }
477
    std::uninitialized_default_construct_n(data() + size_, new_size - size_);
478
    size_ = static_cast<PackedSize<N>>(new_size);
479
    return true;
480
  }
481
482
  // TryCopyFrom sets the vector to a copy of |in| and returns true, or returns
483
  // false if |in| is too large.
484
  [[nodiscard]] bool TryCopyFrom(Span<const T> in) {
485
    if (in.size() > capacity()) {
486
      return false;
487
    }
488
    clear();
489
    std::uninitialized_copy(in.begin(), in.end(), data());
490
    size_ = in.size();
491
    return true;
492
  }
493
494
  // TryPushBack appends |val| to the vector and returns a pointer to the
495
  // newly-inserted value, or nullptr if the vector is at capacity.
496
  [[nodiscard]] T *TryPushBack(T val) {
497
    if (size() >= capacity()) {
498
      return nullptr;
499
    }
500
    T *ret = &data()[size_];
501
    new (ret) T(std::move(val));
502
    size_++;
503
    return ret;
504
  }
505
506
  // The following methods behave like their |Try*| counterparts, but abort the
507
  // program on failure.
508
  void Resize(size_t size) { BSSL_CHECK(TryResize(size)); }
509
  void ResizeForOverwrite(size_t size) {
510
    BSSL_CHECK(TryResizeForOverwrite(size));
511
  }
512
  void CopyFrom(Span<const T> in) { BSSL_CHECK(TryCopyFrom(in)); }
513
  T &PushBack(T val) {
514
    T *ret = TryPushBack(std::move(val));
515
    BSSL_CHECK(ret != nullptr);
516
    return *ret;
517
  }
518
519
  template <typename Pred>
520
  void EraseIf(Pred pred) {
521
    // See if anything needs to be erased at all. This avoids a self-move.
522
    auto iter = std::find_if(begin(), end(), pred);
523
    if (iter == end()) {
524
      return;
525
    }
526
527
    // Elements before the first to be erased may be left as-is.
528
    size_t new_size = iter - begin();
529
    // Swap all subsequent elements in if they are to be kept.
530
    for (size_t i = new_size + 1; i < size(); i++) {
531
      if (!pred((*this)[i])) {
532
        (*this)[new_size] = std::move((*this)[i]);
533
        new_size++;
534
      }
535
    }
536
537
    Shrink(new_size);
538
  }
539
540
 private:
541
  alignas(T) char storage_[sizeof(T[N])];
542
  PackedSize<N> size_ = 0;
543
};
544
545
546
BSSL_NAMESPACE_END
547
548
#endif  // OPENSSL_HEADER_CRYPTO_MEM_INTERNAL_H