Skip to content

Commit db71b4c

Browse files
committed
removed APIs that would index the array after modifying its address
that pattern can fail on some compilers because a stale array address is indexed after the array is resized.
1 parent 97e34c2 commit db71b4c

File tree

2 files changed

+38
-69
lines changed

2 files changed

+38
-69
lines changed

include/array.h

Lines changed: 17 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,17 @@ extern "C" {
4141
#ifndef free
4242
extern void free(void* ptr);
4343
#endif
44-
return size ? (realloc(ptr, size)) : (free(ptr),NULL);
44+
return size ? (realloc(ptr, size)) : (free(ptr),(void*)NULL);
4545
}
4646
#endif
4747

4848

4949
//------------------------------------------------------------------------------
5050

5151

52+
#define array_t(T) T*
53+
54+
5255
// void array_alloc(T*& a, size_t capacity, void (*destructor)(T* begin, T* end))
5356
#define array_alloc(a, capacity, destructor) \
5457
(_array_alloc(_array_ptr((a)), (capacity) * _array_stride((a)), (array_allocator), (_array_destructor_t)(destructor)))
@@ -157,78 +160,38 @@ An assertion will fail if the array is empty.
157160
@hideinitializer **/
158161

159162

160-
// T& array_append(T*& a)
161-
#define array_append(a) \
162-
((a)[ _array_append(_array_ptr((a)), _array_stride((a))) / _array_stride((a)) ])
163+
// void array_append(T*& array, T value)
164+
#define array_append(a, v) \
165+
( _array_append(_array_ptr((a)), _array_stride((a))), array_back(a) = v )
163166
/**< Appends a single element to the dynamic array, allocating additional
164-
storage if necessary. The appended element is uninitialized. Returns a
165-
reference to the appended element.
167+
storage if necessary.
166168
167169
@code{.c}
168170
array_t(int) ia = NULL;
169171
array_alloc(ia, 16, NULL);
170172
// ...
171-
array_append(ia) = 123; // assign value 123 to ia[0]
173+
array_append(ia, 123);
172174
assert(ia[0] == 123);
173175
@endcode
174176
@hideinitializer **/
175177

176178

177-
// T* array_append_n(T*& a, size_t count)
178-
#define array_append_n(a, count) \
179-
((a) + _array_append(_array_ptr((a)), _array_offset((a), (count))) / _array_stride((a)))
180-
/**< Appends count elements to the dynamic array, allocating additional storage
181-
if necessary. Appended elements are uninitialized. Returns a pointer to the
182-
first appended element.
183-
184-
@code{.c}
185-
array_t(int) ia = NULL;
186-
array_alloc(ia, 16, NULL);
187-
// ...
188-
const size_t count = 3;
189-
int* itr = array_append_n(ia, count);
190-
int* end = itr + count;
191-
for (; itr < end; ++itr) { *itr = 0; }
192-
@endcode
193-
@hideinitializer **/
194-
195-
196-
// T& array_insert(T*& a, size_t index)
197-
#define array_insert(a, index) \
198-
((a)[ _array_insert(_array_ptr((a)), _array_offset((a), (index)), _array_stride((a))) / _array_stride((a)) ])
179+
// void array_insert(T*& a, size_t index, T value)
180+
#define array_insert(a, index, v) \
181+
( _array_insert(_array_ptr((a)), _array_offset((a), (index)), _array_stride((a))), (a)[index] = v )
199182
/**< Inserts a single element at the provided index, allocating additional
200-
storage if necessary. The inserted element is uninitialized. Returns a
201-
reference to the inserted element.
183+
storage if necessary.
202184
203185
@code{.c}
204186
array_t(int) ia = NULL;
205187
array_alloc(ia, 16, NULL);
206188
// ...
207-
array_insert(ia, 1) = 123; // assign value 123 to ia[0]
189+
array_insert(ia, 1, 123);
208190
assert(ia[1] == 123);
209191
@endcode
210192
@hideinitializer **/
211193

212194

213-
// T* array_insert_n(T*& a, sizet index, size_t count)
214-
#define array_insert_n(a, index, count) \
215-
((a) + _array_insert(_array_ptr((a)), _array_offset((a), (index)), _array_offset((a), (count))) / _array_stride((a)))
216-
/**< Inserts count elements into the dynamic array starting at index and
217-
allocating additional storage if necessary. Appended elements are
218-
uninitialized. Returns a pointer to the first appended element.
219-
220-
@code{.c}
221-
array_t(int) ia = NULL;
222-
array_alloc(ia, 16, NULL);
223-
// ...
224-
const size_t count = 3;
225-
int* itr = array_insert_n(ia, 0, count);
226-
int* end = itr + count;
227-
for (; itr < end; ++itr) { *itr = 0; }
228-
@endcode
229-
@hideinitializer **/
230-
231-
232195
// void array_remove(T*& a, size_t index)
233196
#define array_remove(a, index) \
234197
(_array_remove(_array_ptr((a)), _array_offset((a), (index)), _array_stride((a))))
@@ -266,7 +229,7 @@ to the array's destructor if it is not NULL.
266229
// T* array_begin(T* array)
267230
#define array_begin(a) (a)
268231
/**< Returns a pointer to the first element of the array, or NULL if the array
269-
is empty or NULL.
232+
is NULL.
270233
@hideinitializer **/
271234

272235

@@ -458,6 +421,7 @@ void _array_reserve(_array_t* a, const size_t capacity) {
458421
_array_assert((*a), "array uninitialized");
459422
if (_array_capacity(a) < capacity) {
460423
_array_grow(a, _array_ceilpow2(capacity));
424+
_array_assert(_array_capacity(a) >= capacity, "_array_grow() failed");
461425
}
462426
}
463427

@@ -598,9 +562,4 @@ void _array_clear(_array_t* const a) {
598562

599563
#if __cplusplus
600564
} // extern "C"
601-
#endif // __cplusplus
602-
603-
604-
#if array_inline
605-
#include "array.inl"
606-
#endif
565+
#endif // __cplusplus

src/tests.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void destructed_element_count_destructor(int* begin, int* end) {
2525

2626

2727
int main(int argc, const char* argv[]) {
28-
int* a = NULL;
28+
array_t(int) a = NULL;
2929
test(array_size(a) == 0);
3030
test(array_capacity(a) == 0);
3131

@@ -34,28 +34,28 @@ int main(int argc, const char* argv[]) {
3434
test(array_capacity(a) == 0);
3535

3636

37-
int* a0 = &array_append(a); *a0 = 1;
37+
array_append(a, 1);
3838
test(array_size(a) == 1);
3939
test(array_capacity(a) >= 1);
4040
test(a[0] == 1);
4141

4242

43-
array_append(a) = 2;
43+
array_append(a, 2);
4444
test(array_size(a) == 2);
4545
test(array_capacity(a) >= 2);
4646
test(a[0] == 1);
4747
test(a[1] == 2);
4848

4949

50-
array_append(a) = 3;
50+
array_append(a, 3);
5151
test(array_size(a) == 3);
5252
test(array_capacity(a) >= 3);
5353
test(a[0] == 1);
5454
test(a[1] == 2);
5555
test(a[2] == 3);
5656

5757

58-
array_insert(a,0) = 0;
58+
array_insert(a, 0, 0);
5959
test(array_size(a) == 4);
6060
test(array_capacity(a) >= 4);
6161
test(a[0] == 0);
@@ -64,7 +64,7 @@ int main(int argc, const char* argv[]) {
6464
test(a[3] == 3);
6565

6666

67-
array_reserve(a,16);
67+
array_reserve(a, 16);
6868
test(array_size(a) == 4);
6969
test(array_capacity(a) == 16);
7070
test(a[0] == 0);
@@ -82,7 +82,7 @@ int main(int argc, const char* argv[]) {
8282
test(a[3] == 3);
8383

8484

85-
array_remove(a,0);
85+
array_remove(a, 0);
8686
test(array_size(a) == 3);
8787
test(array_capacity(a) == 4);
8888
test(a[0] == 1);
@@ -108,18 +108,29 @@ int main(int argc, const char* argv[]) {
108108
destructed_element_count = 0;
109109

110110

111+
array_append(a, 0);
112+
array_append(a, 1);
113+
array_append(a, 2);
114+
test(array_size(a) == 3);
115+
test(array_capacity(a) >= 3);
116+
test(destructed_element_count == 0);
117+
118+
111119
array_free(a);
112120
test(a == NULL);
113121
test(array_size(a) == 0);
114122
test(array_capacity(a) == 0);
123+
test(destructed_element_count == 3);
124+
destructed_element_count = 0;
115125

116126

117127
enum { TEST_LENGTH = 1024 };
118128

119129

120130
array_alloc(a, 0, destructed_element_count_destructor);
121131
for (int i = 0; i < TEST_LENGTH; ++i) {
122-
array_append(a) = i;
132+
array_append(a, i);
133+
test(a[i] == i);
123134
}
124135
test(array_size(a) == TEST_LENGTH);
125136
test(array_capacity(a) >= TEST_LENGTH);
@@ -152,7 +163,7 @@ int main(int argc, const char* argv[]) {
152163

153164
array_alloc(a, 0, destructed_element_count_destructor);
154165
for (int i = 0; i < TEST_LENGTH; ++i) {
155-
array_insert(a,0) = i;
166+
array_insert(a, 0, i);
156167
}
157168
test(array_size(a) == TEST_LENGTH);
158169
test(array_capacity(a) >= TEST_LENGTH);
@@ -165,6 +176,5 @@ int main(int argc, const char* argv[]) {
165176
test(array_capacity(a) == 0);
166177

167178

168-
puts("array.h: passed tests");
169-
return 0;
179+
puts("array tests passed");
170180
}

0 commit comments

Comments
 (0)