[rcl_action] Implement init/fini functions for types#312
Conversation
rcl_action/src/rcl_action/types.c
Outdated
| rcl_action_goal_info_t | ||
| rcl_action_get_zero_initialized_goal_info(void) | ||
| { | ||
| static rcl_action_goal_info_t goal_info = { |
There was a problem hiding this comment.
@jacobperron I wonder if just goal_info = {0} would do for all compilers (as it does for gcc).
There was a problem hiding this comment.
Yes, that will work. For some reason I thought the internal uuid array wasn't initializing with the proper size.
rcl_action/src/rcl_action/types.c
Outdated
| rcl_action_get_zero_initialized_cancel_request(void) | ||
| { | ||
| static rcl_action_cancel_request_t request; | ||
| request.goal_info = rcl_action_get_zero_initialized_goal_info(); |
There was a problem hiding this comment.
@jacobperron this one's tricky, we rely on the compiler to be smart enough to not call rcl_action_get_zero_initialized_goal_info() every single time. How wrong would it be to go with request = {0}; only?
rcl_action/src/rcl_action/types.c
Outdated
| rcl_action_cancel_response_t | ||
| rcl_action_get_zero_initialized_cancel_response(void) | ||
| { | ||
| static rcl_action_cancel_response_t response; |
| TEST(TestActionTypes, test_get_zero_inititalized_goal_info) | ||
| { | ||
| rcl_action_goal_info_t goal_info = rcl_action_get_zero_initialized_goal_info(); | ||
| ASSERT_EQ(sizeof(goal_info.uuid) / sizeof(uint8_t), 16lu); |
There was a problem hiding this comment.
@jacobperron that long literal qualifier is painfully similar to a 1, I wonder which compiler complains if missing.
There was a problem hiding this comment.
Changing to 16u seems okay.
| goal_info.stamp.nanosec = 4567u; | ||
| rcl_action_goal_info_t another_goal_info = rcl_action_get_zero_initialized_goal_info(); | ||
| for (int i = 0; i < 16; ++i) { | ||
| EXPECT_EQ(goal_info.uuid[i], i); |
There was a problem hiding this comment.
@jacobperron what's the rationale for this test? A comment explaining it would be super helpful.
There was a problem hiding this comment.
This was more of a sanity check for myself that creating a second object with the function did not interfere with the first. I'm okay to remove the second goal test if you think it's too pedantic.
There was a problem hiding this comment.
I think it's a good test, but I would add a comment explaining it for the unaware reader.
| TEST(TestActionTypes, test_get_zero_initialized_cancel_response) | ||
| { | ||
| rcl_action_cancel_response_t cancel_response = rcl_action_get_zero_initialized_cancel_response(); | ||
| ASSERT_EQ(cancel_response.goals_canceling.size, 0lu); |
There was a problem hiding this comment.
@jacobperron shouldn't we check for the pointer to be NULL too?
| // Initialize with invalid status array | ||
| rcl_ret_t ret = rcl_action_goal_status_array_init( | ||
| nullptr, | ||
| (size_t) 3, |
There was a problem hiding this comment.
@jacobperron consider making these two above constants for better readability and deduplication.
af424ec to
0a90b35
Compare
rcl_action/src/rcl_action/types.c
Outdated
| rcl_action_goal_status_array_t | ||
| rcl_action_get_zero_initialized_goal_status_array(void) | ||
| { | ||
| static rcl_action_goal_status_array_t status_array; |
| { | ||
| rcl_action_goal_status_array_t status_array = | ||
| rcl_action_get_zero_initialized_goal_status_array(); | ||
| ASSERT_EQ(sizeof(status_array.status_list) / sizeof(rcl_action_goal_status_t), 0u); |
There was a problem hiding this comment.
@jacobperron what's this intent of this test? Won't sizeof(status_array.status_list) be always the same?
|
Also, it looks like MSVC is complaining about linkage again -.- |
Forgot to uncomment the cmake line that should resolve this |
|
Also, it looks like Clang wants braces around initialization of sub-objects in the zero init functions. |
|
Looks like Clang is a bit picky. |
Refactored API. Removed init/fini functions for types that do not necessarily need allocation on the heap. Added unit tests for implementation.
- Simplify and add missing zero initializers - Replace `lu` qualifier with `u` - Add null ptr check in cancel response zero init test - Make size arguments constants
This is to satisfy Clang warnings.
ea0d79c to
7ee1e56
Compare
| { | ||
| rcl_action_goal_status_array_t status_array = | ||
| rcl_action_get_zero_initialized_goal_status_array(); | ||
| // ASSERT_EQ(sizeof(status_array.status_list.data) / sizeof(rcl_action_goal_status_t), 0u); |
sloretz
left a comment
There was a problem hiding this comment.
I'm a bit late with the review, just some minor comments
| ${rcl_action_sources} | ||
| ) | ||
| target_link_libraries(${PROJECT_NAME} | ||
| ${rcl_LIBRARIES} |
There was a problem hiding this comment.
I think ament_target_dependencies("rcl"...) below does this already
| rcl_action_get_zero_initialized_cancel_response(void); | ||
| rcl_action_goal_status_array_fini( | ||
| rcl_action_goal_status_array_t * status_array, | ||
| const rcl_allocator_t allocator); |
There was a problem hiding this comment.
Recommend storing allocator in rcl_action_goal_status_array_t to avoid accidentally deallocating with the wrong allocator.
There was a problem hiding this comment.
Currently, it is defined as:
typedef action_msgs__msg__GoalStatusArray rcl_action_goal_status_array_t;If we want to include space for the allocator, then I suppose we should do something like:
typedef struct rcl_action_goal_status_array_t
{
action_msgs__msg__GoalStatusArray msg;
rcl_allocator_t allocator;
} rcl_action_goal_status_array_t;I can make a follow-up PR to address this and your other comments.
There was a problem hiding this comment.
👍 came here to say this, I noticed it in the API when rebasing my pr (#314).
| rcl_action_cancel_response_fini( | ||
| rcl_action_cancel_response_t * cancel_response, | ||
| rcl_action_server_t * action_server); | ||
| const rcl_allocator_t allocator); |
There was a problem hiding this comment.
Same comment about storing allocator rather than passing it to fini
| RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT); | ||
| RCL_CHECK_ARGUMENT_FOR_NULL(status_array, RCL_RET_INVALID_ARGUMENT, allocator); | ||
| // Ensure status array is zero initialized | ||
| if (status_array->status_list.size > 0) { |
There was a problem hiding this comment.
What should this function do if it is called with num_status = 0?
| RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT); | ||
| RCL_CHECK_ARGUMENT_FOR_NULL(cancel_response, RCL_RET_INVALID_ARGUMENT, allocator); | ||
| // Ensure cancel response is zero initialized | ||
| if (cancel_response->goals_canceling.size > 0) { |
There was a problem hiding this comment.
What should this function do if num_goals_canceling = 0?
There was a problem hiding this comment.
The default allocator uses calloc, which has undefined behavior if the size is zero
If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced.
There was a problem hiding this comment.
Good catch. Perhaps it should return RCL_RET_INVALID_ARGUMENT?
Connects to #306.
Refactored API. Removed init/fini functions for types that do not necessarily need allocation on the heap.
Added unit tests for implementation.