-
Notifications
You must be signed in to change notification settings - Fork 103
Ensure rcutils_char_array_t is null-termiated after memcpy #493
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
base: rolling
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -194,20 +194,25 @@ rcutils_char_array_vsprintf(rcutils_char_array_t * char_array, const char * form | |
rcutils_ret_t | ||
rcutils_char_array_memcpy(rcutils_char_array_t * char_array, const char * src, size_t n) | ||
{ | ||
rcutils_ret_t ret = rcutils_char_array_expand_as_needed(char_array, n); | ||
size_t new_length = n; | ||
if (n > 0 && '\0' != src[n - 1]) { | ||
new_length += 1; | ||
} | ||
rcutils_ret_t ret = rcutils_char_array_expand_as_needed(char_array, new_length); | ||
if (ret != RCUTILS_RET_OK) { | ||
// rcutils_char_array_expand_as needed already set the error | ||
return ret; | ||
} | ||
memcpy(char_array->buffer, src, n); | ||
char_array->buffer_length = n; | ||
char_array->buffer[new_length - 1] = '\0'; // always have an ending | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this line is my main complaint with this change, consider this additional test code: {
rcutils_ret_t ret = rcutils_char_array_init(&char_array, 8, &allocator);
ASSERT_EQ(RCUTILS_RET_OK, ret);
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_strcpy(&char_array, "hello world"));
EXPECT_STREQ("hello world", char_array.buffer);
EXPECT_EQ(12lu, char_array.buffer_length);
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_memcpy(&char_array, "HELLO", strlen("HELLO")));
EXPECT_STREQ("HELLO world", char_array.buffer);
EXPECT_EQ(12lu, char_array.buffer_length);
} Personally I would expect the result (with memcpy) to be "HELLO world", but it's not:
Maybe this could be addressed with only setting the null-terminator when the array was expanded? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without this PR, the buffer would be in the state you're expecting it to be, but the So unless the memory we're copying in has a single null character right at the end, we'll be in an inconsistent state. |
||
char_array->buffer_length = new_length; | ||
return RCUTILS_RET_OK; | ||
} | ||
|
||
rcutils_ret_t | ||
rcutils_char_array_strcpy(rcutils_char_array_t * char_array, const char * src) | ||
{ | ||
return rcutils_char_array_memcpy(char_array, src, strlen(src) + 1); | ||
return rcutils_char_array_memcpy(char_array, src, strlen(src)); | ||
} | ||
|
||
rcutils_ret_t | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love the fact that the new length will depend on the content being copied, and it also prevents you from intentionally creating a character array without a null terminating character (maybe you're tracking the length separately and build a string out of intermediate string fragments or something idk). I suppose it's fine because you can use the
rcutils_uint8_array_t
for that, but it still feels weird.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd question whether non-terminated strings is something this type is intended to support at all. The
_strcat
and_strncat
functions expect the character at indexbuffer_length - 1
to be a terminator and overwrite it with the beginning of the source string.Also, theOh, actually it only does that if it doesn't own the buffer?_resize
function writes a null terminator to the buffer when the string is shortened.The argument against changing the allocated size based on content is valid. I'd say we should balance that against the risk of an inconsistent state we live with today.