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.
This commit is contained in:
parent
28d2f1d0df
commit
9d3893459f
3 changed files with 41 additions and 0 deletions
|
@ -942,6 +942,13 @@ size_t strlcat(char *dst, const char *src, size_t size) {
|
||||||
return dstLength + (src - srcStart);
|
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
|
} // End of namespace Common
|
||||||
|
|
||||||
// Portable implementation of stricmp / strcasecmp / strcmpi.
|
// Portable implementation of stricmp / strcasecmp / strcmpi.
|
||||||
|
|
11
common/str.h
11
common/str.h
|
@ -444,6 +444,17 @@ size_t strlcpy(char *dst, const char *src, size_t size);
|
||||||
*/
|
*/
|
||||||
size_t strlcat(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.
|
* Convenience wrapper for tag2string which "returns" a C string.
|
||||||
* Note: It is *NOT* safe to do anything with the return value other than directly
|
* Note: It is *NOT* safe to do anything with the return value other than directly
|
||||||
|
|
|
@ -403,6 +403,29 @@ class StringTestSuite : public CxxTest::TestSuite
|
||||||
TS_ASSERT_EQUALS(strcmp(test4, resultString), 0);
|
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() {
|
void test_scumm_stricmp() {
|
||||||
TS_ASSERT_EQUALS(scumm_stricmp("abCd", "abCd"), 0);
|
TS_ASSERT_EQUALS(scumm_stricmp("abCd", "abCd"), 0);
|
||||||
TS_ASSERT_EQUALS(scumm_stricmp("abCd", "ABCd"), 0);
|
TS_ASSERT_EQUALS(scumm_stricmp("abCd", "ABCd"), 0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue