diff options
author | Colin Snover | 2016-11-26 12:56:25 -0600 |
---|---|---|
committer | Willem Jan Palenstijn | 2017-01-05 22:07:24 +0100 |
commit | 9d3893459f34b6ada2dad2d9d27216c774a7c4bd (patch) | |
tree | cf09a5960aa37cff29666211da50fd488c5f05e9 | |
parent | 28d2f1d0df4a62c622a714e82ec6a7ab04967730 (diff) | |
download | scummvm-rg350-9d3893459f34b6ada2dad2d9d27216c774a7c4bd.tar.gz scummvm-rg350-9d3893459f34b6ada2dad2d9d27216c774a7c4bd.tar.bz2 scummvm-rg350-9d3893459f34b6ada2dad2d9d27216c774a7c4bd.zip |
COMMON: Add strnlen for safer C string length reads
This API is intended for use in cases where C strings come
from untrusted sources like game files, where malformed data
missing the null terminator would cause strlen to read out of
bounds.
-rw-r--r-- | common/str.cpp | 7 | ||||
-rw-r--r-- | common/str.h | 11 | ||||
-rw-r--r-- | test/common/str.h | 23 |
3 files changed, 41 insertions, 0 deletions
diff --git a/common/str.cpp b/common/str.cpp index 90bd539790..3a0fd6a08e 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -942,6 +942,13 @@ size_t strlcat(char *dst, const char *src, size_t size) { return dstLength + (src - srcStart); } +size_t strnlen(const char *src, size_t maxSize) { + size_t counter = 0; + while (counter != maxSize && *src++) + ++counter; + return counter; +} + } // End of namespace Common // Portable implementation of stricmp / strcasecmp / strcmpi. diff --git a/common/str.h b/common/str.h index d55ba072a9..ba1e0b8341 100644 --- a/common/str.h +++ b/common/str.h @@ -445,6 +445,17 @@ size_t strlcpy(char *dst, const char *src, size_t size); size_t strlcat(char *dst, const char *src, size_t size); /** + * Determine the length of a string up to a maximum of `maxSize` characters. + * This should be used instead of `strlen` when reading the length of a C string + * from potentially unsafe or corrupt sources, like game assets. + * + * @param src The source string. + * @param maxSize The maximum size of the string. + * @return The length of the string. + */ +size_t strnlen(const char *src, size_t maxSize); + +/** * Convenience wrapper for tag2string which "returns" a C string. * Note: It is *NOT* safe to do anything with the return value other than directly * copying or printing it. diff --git a/test/common/str.h b/test/common/str.h index c59c5a5efd..b6080fe3be 100644 --- a/test/common/str.h +++ b/test/common/str.h @@ -403,6 +403,29 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(strcmp(test4, resultString), 0); } + void test_strnlen() { + static const char * const testString = "123"; + TS_ASSERT_EQUALS(Common::strnlen(testString, 0), 0); + TS_ASSERT_EQUALS(Common::strnlen(testString, 1), 1); + TS_ASSERT_EQUALS(Common::strnlen(testString, 2), 2); + TS_ASSERT_EQUALS(Common::strnlen(testString, 3), 3); + TS_ASSERT_EQUALS(Common::strnlen(testString, 4), 3); + + const char testArray[4] = { '1', '2', '3', '4' }; + TS_ASSERT_EQUALS(Common::strnlen(testArray, 0), 0); + TS_ASSERT_EQUALS(Common::strnlen(testArray, 1), 1); + TS_ASSERT_EQUALS(Common::strnlen(testArray, 2), 2); + TS_ASSERT_EQUALS(Common::strnlen(testArray, 3), 3); + TS_ASSERT_EQUALS(Common::strnlen(testArray, 4), 4); + + const char testArray2[4] = { '1', '\0', '3', '4' }; + TS_ASSERT_EQUALS(Common::strnlen(testArray2, 0), 0); + TS_ASSERT_EQUALS(Common::strnlen(testArray2, 1), 1); + TS_ASSERT_EQUALS(Common::strnlen(testArray2, 2), 1); + TS_ASSERT_EQUALS(Common::strnlen(testArray2, 3), 1); + TS_ASSERT_EQUALS(Common::strnlen(testArray2, 4), 1); + } + void test_scumm_stricmp() { TS_ASSERT_EQUALS(scumm_stricmp("abCd", "abCd"), 0); TS_ASSERT_EQUALS(scumm_stricmp("abCd", "ABCd"), 0); |