Skip to content

Commit 6349f20

Browse files
committed
Implement rcutils_strnlen.
This is a portable version that uses memchr as its underlying implementation. Signed-off-by: Chris Lalancette <[email protected]>
1 parent a8b880a commit 6349f20

7 files changed

+85
-30
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ set(rcutils_sources
7272
src/strerror.c
7373
src/string_array.c
7474
src/string_map.c
75+
src/strnlen.c
7576
src/testing/fault_injection.c
7677
src/time.c
7778
${time_impl_c}
@@ -276,7 +277,7 @@ if(BUILD_TESTING)
276277
)
277278
if(TARGET test_error_handling_helpers)
278279
target_include_directories(test_error_handling_helpers PUBLIC include)
279-
target_link_libraries(test_error_handling_helpers osrf_testing_tools_cpp::memory_tools)
280+
target_link_libraries(test_error_handling_helpers ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools)
280281
endif()
281282

282283
ament_add_gtest(test_split

include/rcutils/error_handling.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ extern "C"
2222
{
2323
#endif
2424

25-
#ifndef __STDC_WANT_LIB_EXT1__
26-
#define __STDC_WANT_LIB_EXT1__ 1 // indicate we would like strnlen_s if available
27-
#endif
2825
#include <assert.h>
2926
#include <stdbool.h>
3027
#include <stddef.h>
@@ -36,23 +33,18 @@ extern "C"
3633
#include "rcutils/allocator.h"
3734
#include "rcutils/macros.h"
3835
#include "rcutils/snprintf.h"
36+
#include "rcutils/strnlen.h"
3937
#include "rcutils/testing/fault_injection.h"
4038
#include "rcutils/types/rcutils_ret.h"
4139
#include "rcutils/visibility_control.h"
4240

43-
#ifdef __STDC_LIB_EXT1__
4441
/// Write the given msg out to stderr, limiting the buffer size in the `fwrite`.
4542
/**
4643
* This ensures that there is an upper bound to a buffer overrun if `msg` is
4744
* non-null terminated.
4845
*/
4946
#define RCUTILS_SAFE_FWRITE_TO_STDERR(msg) \
50-
do {fwrite(msg, sizeof(char), strnlen_s(msg, 4096), stderr);} while (0)
51-
#else
52-
/// Write the given msg out to stderr.
53-
#define RCUTILS_SAFE_FWRITE_TO_STDERR(msg) \
54-
do {fwrite(msg, sizeof(char), strlen(msg), stderr);} while (0)
55-
#endif
47+
do {fwrite(msg, sizeof(char), rcutils_strnlen(msg, 4096), stderr);} while (0)
5648

5749
/// Set the error message to stderr using a format string and format arguments.
5850
/**

include/rcutils/strnlen.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2023 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/// \file
16+
17+
#ifndef RCUTILS__STRNLEN_H_
18+
#define RCUTILS__STRNLEN_H_
19+
20+
#ifdef __cplusplus
21+
extern "C"
22+
{
23+
#endif
24+
25+
#include "rcutils/macros.h"
26+
#include "rcutils/visibility_control.h"
27+
28+
/// Determine the length of a fixed-size string
29+
/**
30+
* \param[in] s Null terminated string to find the length of.
31+
* \param[in] maxlen Maximum length to look to find the trailing \0.
32+
* \return The length of the string if it is less than maxlen, or
33+
* \return maxlen if there is no \0 among the first maxlen characters.
34+
*/
35+
RCUTILS_PUBLIC
36+
RCUTILS_WARN_UNUSED
37+
size_t
38+
rcutils_strnlen(const char * s, size_t maxlen);
39+
40+
#ifdef __cplusplus
41+
}
42+
#endif
43+
44+
#endif // RCUTILS__STRNLEN_H_

src/error_handling.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ extern "C"
2525
#include <stdbool.h>
2626
#include <stdio.h>
2727
#include <stdlib.h>
28-
#define __STDC_WANT_LIB_EXT1__ 1
2928
#include <string.h>
3029

3130
#include <rcutils/allocator.h>
3231
#include <rcutils/macros.h>
3332
#include <rcutils/strdup.h>
33+
#include <rcutils/strnlen.h>
3434

3535
// RCUTILS_REPORT_ERROR_HANDLING_ERRORS and RCUTILS_WARN_ON_TRUNCATION are set in the header below
3636
#include "./error_handling_helpers.h"
@@ -199,11 +199,7 @@ rcutils_set_error_state(
199199
error_state.line_number = line_number;
200200
#if RCUTILS_REPORT_ERROR_HANDLING_ERRORS
201201
// Only warn of overwritting if the new error is different from the old ones.
202-
#ifdef __STDC_LIB_EXT1__
203-
size_t characters_to_compare = strnlen_s(error_string, RCUTILS_ERROR_MESSAGE_MAX_LENGTH);
204-
#else
205-
size_t characters_to_compare = strnlen(error_string, RCUTILS_ERROR_MESSAGE_MAX_LENGTH);
206-
#endif
202+
size_t characters_to_compare = rcutils_strnlen(error_string, RCUTILS_ERROR_MESSAGE_MAX_LENGTH);
207203
// assumption is that message length is <= max error string length
208204
static_assert(
209205
sizeof(gtls_rcutils_error_state.message) <= sizeof(gtls_rcutils_error_string.str),

src/error_handling_helpers.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
#endif
3737
#include <assert.h>
3838
#include <stdlib.h>
39-
#define __STDC_WANT_LIB_EXT1__ 1
4039
#include <string.h>
4140

4241
#include <rcutils/error_handling.h>
42+
#include <rcutils/strnlen.h>
4343

4444
#ifdef __cplusplus
4545
extern "C"
@@ -131,11 +131,7 @@ __rcutils_convert_uint64_t_into_c_str(uint64_t number, char * buffer, size_t buf
131131
buffer[i] = '\0';
132132

133133
// reverse the string in place
134-
#ifdef __STDC_LIB_EXT1__
135-
__rcutils_reverse_str(buffer, strnlen_s(buffer, 21));
136-
#else
137-
__rcutils_reverse_str(buffer, strnlen(buffer, 21));
138-
#endif
134+
__rcutils_reverse_str(buffer, rcutils_strnlen(buffer, 21));
139135
}
140136

141137
// do not use externally, internal function which is only to be used by error_handling.c

src/strnlen.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2023 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <string.h>
16+
17+
#include "rcutils/strnlen.h"
18+
19+
size_t
20+
rcutils_strnlen(const char * s, size_t maxlen)
21+
{
22+
const char * found = memchr(s, '\0', maxlen);
23+
return found ? (size_t)(found - s) : maxlen;
24+
}

test/test_error_handling_helpers.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include "osrf_testing_tools_cpp/memory_tools/gtest_quickstart.hpp"
2020

21+
#include "rcutils/strnlen.h"
22+
2123
#include "../src/error_handling_helpers.h"
2224

2325
TEST(test_error_handling, copy_string) {
@@ -32,7 +34,7 @@ TEST(test_error_handling, copy_string) {
3234
written = __rcutils_copy_string(buffer, 3, "0123456789");
3335
});
3436
EXPECT_EQ(written, 2u);
35-
EXPECT_EQ(strnlen(buffer, sizeof(buffer)), 2u);
37+
EXPECT_EQ(rcutils_strnlen(buffer, sizeof(buffer)), 2u);
3638
EXPECT_STREQ(buffer, "01");
3739

3840
// normal truncation, 1 short of buffer length
@@ -41,7 +43,7 @@ TEST(test_error_handling, copy_string) {
4143
written = __rcutils_copy_string(buffer, 9, "0123456789");
4244
});
4345
EXPECT_EQ(written, 8u);
44-
EXPECT_EQ(strnlen(buffer, sizeof(buffer)), 8u);
46+
EXPECT_EQ(rcutils_strnlen(buffer, sizeof(buffer)), 8u);
4547
EXPECT_STREQ(buffer, "01234567");
4648

4749
// input smaller than buffer, 1 short of buffer length
@@ -50,7 +52,7 @@ TEST(test_error_handling, copy_string) {
5052
written = __rcutils_copy_string(buffer, 9, "");
5153
});
5254
EXPECT_EQ(written, 0u);
53-
EXPECT_EQ(strnlen(buffer, sizeof(buffer)), 0u);
55+
EXPECT_EQ(rcutils_strnlen(buffer, sizeof(buffer)), 0u);
5456
EXPECT_STREQ(buffer, "");
5557

5658
// copy where src and dst overlap (testing use of memmove vs memcpy)
@@ -65,7 +67,7 @@ TEST(test_error_handling, copy_string) {
6567
written = __rcutils_copy_string(buffer, sizeof(buffer), buffer + 3);
6668
});
6769
EXPECT_EQ(written, 6u);
68-
EXPECT_EQ(strnlen(buffer, sizeof(buffer)), (sizeof(buffer) - 1) - 3);
70+
EXPECT_EQ(rcutils_strnlen(buffer, sizeof(buffer)), (sizeof(buffer) - 1) - 3);
6971
EXPECT_STREQ(buffer, "456789");
7072
}
7173

@@ -75,23 +77,23 @@ TEST(test_error_handling, reverse_str) {
7577
char buffer[] = "even";
7678
EXPECT_NO_MEMORY_OPERATIONS(
7779
{
78-
__rcutils_reverse_str(buffer, strnlen(buffer, sizeof(buffer)));
80+
__rcutils_reverse_str(buffer, rcutils_strnlen(buffer, sizeof(buffer)));
7981
});
8082
EXPECT_STREQ(buffer, "neve");
8183
}
8284
{
8385
char buffer[] = "reverseme";
8486
EXPECT_NO_MEMORY_OPERATIONS(
8587
{
86-
__rcutils_reverse_str(buffer, strnlen(buffer, sizeof(buffer)));
88+
__rcutils_reverse_str(buffer, rcutils_strnlen(buffer, sizeof(buffer)));
8789
});
8890
EXPECT_STREQ(buffer, "emesrever");
8991
}
9092
{
9193
char buffer[] = "a";
9294
EXPECT_NO_MEMORY_OPERATIONS(
9395
{
94-
__rcutils_reverse_str(buffer, strnlen(buffer, sizeof(buffer)));
96+
__rcutils_reverse_str(buffer, rcutils_strnlen(buffer, sizeof(buffer)));
9597
});
9698
EXPECT_STREQ(buffer, "a");
9799
}

0 commit comments

Comments
 (0)