4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 #include "checked-overflow.h"
42 #include "posix_memalign.h"
47 calculate_capacity (struct generic_vector
*v
, size_t n
, size_t itemsize
,
48 size_t *newcap_r
, size_t *newbytes_r
)
50 size_t reqcap
, reqbytes
, newcap
, newbytes
, t
;
52 /* New capacity requested. We must allocate this minimum (or fail).
54 * reqbytes = reqcap * itemsize
56 if (ADD_OVERFLOW (v
->cap
, n
, &reqcap
) ||
57 MUL_OVERFLOW (reqcap
, itemsize
, &reqbytes
)) {
62 /* However for the sake of optimization, scale buffer by 3/2 so that
63 * repeated reservations don't call realloc often.
64 * newcap = v->cap + (v->cap + 1) / 2
65 * newbytes = newcap * itemsize
67 if (ADD_OVERFLOW (v
->cap
, 1u, &t
) ||
68 ADD_OVERFLOW (v
->cap
, t
/2, &newcap
) ||
69 MUL_OVERFLOW (newcap
, itemsize
, &newbytes
) ||
70 newbytes
< reqbytes
) {
71 /* If that either overflows or is less than the minimum requested,
72 * fall back to the requested capacity.
79 *newbytes_r
= newbytes
;
84 generic_vector_reserve (struct generic_vector
*v
, size_t n
, size_t itemsize
)
87 size_t newcap
, newbytes
;
89 if (calculate_capacity (v
, n
, itemsize
, &newcap
, &newbytes
) == -1)
92 newptr
= realloc (v
->ptr
, newbytes
);
101 /* Always allocates a buffer which is page aligned (both base and size). */
103 generic_vector_reserve_page_aligned (struct generic_vector
*v
,
104 size_t n
, size_t itemsize
)
108 size_t newcap
, newbytes
;
110 size_t extra
, extra_items
;
112 pagesize
= sysconf (_SC_PAGESIZE
);
113 assert (pagesize
> 1);
115 assert (pagesize
% itemsize
== 0);
117 if (calculate_capacity (v
, n
, itemsize
, &newcap
, &newbytes
) == -1)
120 /* If the new size (in bytes) is not a full page then we have to
121 * round up to the next page.
123 extra
= newbytes
& (pagesize
- 1);
125 extra_items
= (pagesize
- extra
) / itemsize
;
127 if (ADD_OVERFLOW (newcap
, extra_items
, &newcap
) ||
128 ADD_OVERFLOW (newbytes
, extra_items
* itemsize
, &newbytes
)) {
134 if ((r
= posix_memalign (&newptr
, pagesize
, newbytes
)) != 0) {
139 /* How much to copy here?
141 * vector_reserve always makes the buffer larger so we don't have to
142 * deal with the case of a shrinking buffer.
144 * Like the underlying realloc we do not have to zero the newly
147 * However (like realloc) we have to copy the existing elements even
148 * those that are not allocated and only reserved (between 'len' and
151 * The spec of vector is not clear on the last two points, but
152 * existing code depends on this undocumented behaviour.
154 memcpy (newptr
, v
->ptr
, v
->cap
* itemsize
);