2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-09 01:07:43 +00:00

CStringExtras: Prevent potential out of bounds reads with CompareCaseInsensitive

The strcasecmp and _stricmp functions expect the passed in strings to
be null-terminated, however we we're also exposing a std::string_view
overload for that function. std::string_view instances aren't required
to be null-terminated, so this makes the interface a little unsafe.

We can use std::lexicographical_compare() to provide the same behavior
and also properly handle the case of non-null-terminated strings.
This commit is contained in:
Lioncash
2019-09-14 11:14:51 -04:00
parent 002ca71104
commit 0d2b2f45a8
5 changed files with 30 additions and 18 deletions

View File

@@ -1,21 +1,30 @@
#pragma once
#include <algorithm>
#include <cctype>
#include <string>
#include <cstring>
namespace urde {
class CStringExtras {
public:
static int CompareCaseInsensitive(const char* a, const char* b) {
#if _WIN32
return _stricmp(a, b);
#else
return strcasecmp(a, b);
#endif
}
static int CompareCaseInsensitive(std::string_view a, std::string_view b) {
return CompareCaseInsensitive(a.data(), b.data());
// Checks if the provided views into string data can be considered equal or not based on
// whether or not all their characters are lexicographically equal to one another in
// a character insensitive manner.
//
// NOTE: This differs slightly from the actual version of this function within the game executable
// in order to better accomodate string views and potentially non-null-terminated string data.
//
// In the game executable, the function essentially behaves like strcasecmp in that it returns
// an int indicating whether or not the first argument is lexicographically less than, equal to,
// or greater than the second argument. Given no usages in the code depend on the less than or
// greater than cases, but rather just care about whether or not the strings are equal to one
// another, this is a safe change to make.
//
static bool CompareCaseInsensitive(std::string_view a, std::string_view b) {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), [](char lhs, char rhs) {
return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
});
}
static int IndexOfSubstring(std::string_view haystack, std::string_view needle) {