Skip to content

Commit 87321fa

Browse files
committed
Ensure rcutils_char_array_t is null-termiated after memcpy
When copying a substring from another string, we need to explicitly verify that the new string will contain a null terminator, which may necessitate allocation of an additional byte. Signed-off-by: Scott K Logan <[email protected]>
1 parent 2f3252e commit 87321fa

File tree

3 files changed

+31
-4
lines changed

3 files changed

+31
-4
lines changed

include/rcutils/types/char_array.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ rcutils_char_array_strcat(rcutils_char_array_t * char_array, const char * src);
208208
/// Copy memory to buffer.
209209
/**
210210
* This function is equivalent to `memcpy(char_array->buffer, src, n)` except that the buffer
211-
* grows as needed so a user doesn't have to worry about overflow.
211+
* grows as needed so a user doesn't have to worry about overflow and a null byte is appended if
212+
* necessary.
212213
*
213214
* \param[inout] char_array pointer to the instance of rcutils_char_array_t which is being resized
214215
* \param[in] src the memory to be copied from

src/char_array.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -194,20 +194,25 @@ rcutils_char_array_vsprintf(rcutils_char_array_t * char_array, const char * form
194194
rcutils_ret_t
195195
rcutils_char_array_memcpy(rcutils_char_array_t * char_array, const char * src, size_t n)
196196
{
197-
rcutils_ret_t ret = rcutils_char_array_expand_as_needed(char_array, n);
197+
size_t new_length = n;
198+
if (n > 0 && '\0' != src[n - 1]) {
199+
new_length += 1;
200+
}
201+
rcutils_ret_t ret = rcutils_char_array_expand_as_needed(char_array, new_length);
198202
if (ret != RCUTILS_RET_OK) {
199203
// rcutils_char_array_expand_as needed already set the error
200204
return ret;
201205
}
202206
memcpy(char_array->buffer, src, n);
203-
char_array->buffer_length = n;
207+
char_array->buffer[new_length - 1] = '\0'; // always have an ending
208+
char_array->buffer_length = new_length;
204209
return RCUTILS_RET_OK;
205210
}
206211

207212
rcutils_ret_t
208213
rcutils_char_array_strcpy(rcutils_char_array_t * char_array, const char * src)
209214
{
210-
return rcutils_char_array_memcpy(char_array, src, strlen(src) + 1);
215+
return rcutils_char_array_memcpy(char_array, src, strlen(src));
211216
}
212217

213218
rcutils_ret_t

test/test_char_array.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,27 @@ TEST_F(ArrayCharTest, vsprintf_fail) {
130130
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_fini(&char_array));
131131
}
132132

133+
TEST_F(ArrayCharTest, memcpy) {
134+
rcutils_allocator_t failing_allocator = get_failing_allocator();
135+
rcutils_ret_t ret = rcutils_char_array_init(&char_array, 8, &allocator);
136+
ASSERT_EQ(RCUTILS_RET_OK, ret);
137+
138+
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_memcpy(&char_array, "1234", 4));
139+
EXPECT_STREQ("1234", char_array.buffer);
140+
EXPECT_EQ(5lu, char_array.buffer_length);
141+
142+
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_memcpy(&char_array, "1234", 5));
143+
EXPECT_STREQ("1234", char_array.buffer);
144+
EXPECT_EQ(5lu, char_array.buffer_length);
145+
146+
char_array.allocator = failing_allocator;
147+
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, rcutils_char_array_memcpy(&char_array, "123456789", 9));
148+
rcutils_reset_error();
149+
150+
char_array.allocator = allocator;
151+
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_fini(&char_array));
152+
}
153+
133154
TEST_F(ArrayCharTest, strcpy) {
134155
rcutils_allocator_t failing_allocator = get_failing_allocator();
135156
rcutils_ret_t ret = rcutils_char_array_init(&char_array, 8, &allocator);

0 commit comments

Comments
 (0)