diff --git a/util/stdlib/strnlen.cc b/util/stdlib/strnlen.cc new file mode 100644 index 00000000..b17796bb --- /dev/null +++ b/util/stdlib/strnlen.cc @@ -0,0 +1,37 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/stdlib/strnlen.h" + +namespace crashpad { + +#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 +size_t strnlen(const char* string, size_t max_length) { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (::strnlen) { + return ::strnlen(string, max_length); + } +#endif + + for (size_t index = 0; index < max_length; ++index) { + if (string[index] == '\0') { + return index; + } + } + + return max_length; +} +#endif + +} // namespace crashpad diff --git a/util/stdlib/strnlen.h b/util/stdlib/strnlen.h new file mode 100644 index 00000000..f1bbe638 --- /dev/null +++ b/util/stdlib/strnlen.h @@ -0,0 +1,49 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_STDLIB_STRNLEN_H_ +#define CRASHPAD_UTIL_STDLIB_STRNLEN_H_ + +#include + +#include "build/build_config.h" + +#if defined(OS_MACOSX) +#include +#endif + +namespace crashpad { + +//! \brief Returns the length of a string, not to exceed a maximum. +//! +//! \param[in] string The string whose length is to be calculated. +//! \param[in] max_length The maximum length to return. +//! +//! \return The length of \a string, determined as the index of the first `NUL` +//! byte found, not exceeding \a max_length. +//! +//! \note This function is provided because it was introduced in POSIX.1-2008, +//! and not all systems’ standard libraries provide an implementation. +size_t strnlen(const char* string, size_t max_length); + +#if !defined(OS_MACOSX) || \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 +inline size_t strnlen(const char* string, size_t max_length) { + return ::strnlen(string, max_length); +} +#endif + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STDLIB_STRNLEN_H_ diff --git a/util/stdlib/strnlen_test.cc b/util/stdlib/strnlen_test.cc new file mode 100644 index 00000000..f5b6845b --- /dev/null +++ b/util/stdlib/strnlen_test.cc @@ -0,0 +1,41 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/stdlib/strnlen.h" + +#include + +#include "gtest/gtest.h" + +namespace { + +TEST(strnlen, strnlen) { + const char kTestBuffer[] = "abc\0d"; + ASSERT_EQ(3u, strlen(kTestBuffer)); + EXPECT_EQ(0u, crashpad::strnlen(kTestBuffer, 0)); + EXPECT_EQ(1u, crashpad::strnlen(kTestBuffer, 1)); + EXPECT_EQ(2u, crashpad::strnlen(kTestBuffer, 2)); + EXPECT_EQ(3u, crashpad::strnlen(kTestBuffer, 3)); + EXPECT_EQ(3u, crashpad::strnlen(kTestBuffer, 4)); + EXPECT_EQ(3u, crashpad::strnlen(kTestBuffer, 5)); + EXPECT_EQ(3u, crashpad::strnlen(kTestBuffer, 6)); + + const char kEmptyBuffer[] = "\0"; + ASSERT_EQ(0u, strlen(kEmptyBuffer)); + EXPECT_EQ(0u, crashpad::strnlen(kEmptyBuffer, 0)); + EXPECT_EQ(0u, crashpad::strnlen(kEmptyBuffer, 1)); + EXPECT_EQ(0u, crashpad::strnlen(kEmptyBuffer, 2)); +} + +} // namespace diff --git a/util/util.gyp b/util/util.gyp index 4a6c56e7..7af42568 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -74,6 +74,8 @@ 'stdlib/pointer_container.h', 'stdlib/strlcpy.cc', 'stdlib/strlcpy.h', + 'stdlib/strnlen.cc', + 'stdlib/strnlen.h', ], }, { @@ -136,6 +138,7 @@ 'numeric/in_range_cast_test.cc', 'posix/process_util_test.cc', 'stdlib/strlcpy_test.cc', + 'stdlib/strnlen_test.cc', 'test/mac/mach_multiprocess_test.cc', 'test/multiprocess_test.cc', ],