mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 18:49:51 +01:00
CmdLine: Take integer parameters in hex too, and refuse trailing junk
They were read with sscanf("%d"), which stops at the first character it
can't use, so --disable-hle=0x110 was accepted as 0 and quietly ran
everything on our HLE. Now decimal or 0x hex, optionally signed, and the
whole value has to parse. Up to 0xFFFFFFFF is taken, for full masks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
6c8c71a125
commit
ddfd3bcfb9
2 files changed
+57
-1
No files matched your search
+30
-1
@@ -1,5 +1,6 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
@@ -51,6 +52,34 @@ enum class ParseParamResult {
|
||||
BadValue,
|
||||
};
|
||||
|
||||
// Decimal, or hex with 0x, optionally signed. Not base 0, which would read a leading 0 as octal.
|
||||
// Up to 0xFFFFFFFF is accepted so a full 32-bit mask can be given, and wraps into the int.
|
||||
static bool ParseIntParam(const std::string &value, int *out) {
|
||||
const char *p = value.c_str();
|
||||
bool negative = false;
|
||||
if (*p == '-' || *p == '+') {
|
||||
negative = *p == '-';
|
||||
p++;
|
||||
}
|
||||
int base = 10;
|
||||
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
|
||||
base = 16;
|
||||
p += 2;
|
||||
}
|
||||
// strtoull would take another sign or leading spaces here.
|
||||
if (!isxdigit((unsigned char)*p)) {
|
||||
return false;
|
||||
}
|
||||
char *end = nullptr;
|
||||
errno = 0;
|
||||
const unsigned long long magnitude = strtoull(p, &end, base);
|
||||
if (*end != '\0' || errno == ERANGE || magnitude > (negative ? 0x80000000ULL : 0xFFFFFFFFULL)) {
|
||||
return false;
|
||||
}
|
||||
*out = negative ? (int)(0 - (uint32_t)magnitude) : (int)(uint32_t)magnitude;
|
||||
return true;
|
||||
}
|
||||
|
||||
ParseParamResult SetValue(CommandLineOptions *options, const CommandLineParam ¶m, const std::string &value) {
|
||||
uint8_t *optionsPtr = reinterpret_cast<uint8_t *>(options);
|
||||
switch (param.type) {
|
||||
@@ -77,7 +106,7 @@ ParseParamResult SetValue(CommandLineOptions *options, const CommandLineParam &p
|
||||
{
|
||||
// Not std::stoi - that throws on junk, which takes the process down with no diagnostic.
|
||||
int v;
|
||||
if (sscanf(value.c_str(), "%d", &v) != 1) {
|
||||
if (!ParseIntParam(value, &v)) {
|
||||
PRINT_STDERR("Error: Invalid value for integer parameter --%s: '%s'.\n", param.longName, value.c_str());
|
||||
return ParseParamResult::BadValue;
|
||||
}
|
||||
|
||||
@@ -3391,6 +3391,33 @@ bool TestCmdLine() {
|
||||
EXPECT_TRUE(options.memStickInserted.has_value());
|
||||
EXPECT_FALSE(options.memStickInserted.value_or(true));
|
||||
}
|
||||
// Integers take decimal or 0x hex. A leading 0 is still decimal, and a full 32-bit mask wraps
|
||||
// into the int rather than being refused.
|
||||
{
|
||||
const char *argv[] = {
|
||||
"ppsspp",
|
||||
"--disable-hle=0x110",
|
||||
"--force-hle=0xFFFFFFFF",
|
||||
"--cpu-mhz=0333",
|
||||
"--resolution-scale=-2",
|
||||
};
|
||||
int argc = ARRAY_SIZE(argv);
|
||||
CommandLineOptions options;
|
||||
EXPECT_EQ_INT((int)options.Parse(argc, argv, CmdLineMode::Headless), (int)CommandLineParseResult::Continue);
|
||||
EXPECT_EQ_INT(options.disableHLE.value_or(0), 0x110);
|
||||
EXPECT_EQ_INT(options.forceHLE.value_or(0), -1);
|
||||
EXPECT_EQ_INT(options.lockedCPUSpeed.value_or(0), 333);
|
||||
EXPECT_EQ_INT(options.resolutionScale.value_or(0), -2);
|
||||
}
|
||||
// Trailing junk used to be ignored, so 0x110 quietly meant 0.
|
||||
{
|
||||
const char *bad[] = { "--disable-hle=0x110junk", "--disable-hle=12abc", "--disable-hle=0x", "--disable-hle= 5", "--disable-hle=0x100000000", "--disable-hle=--1" };
|
||||
for (const char *arg : bad) {
|
||||
const char *argv[] = { "ppsspp", arg };
|
||||
CommandLineOptions options;
|
||||
EXPECT_EQ_INT((int)options.Parse(ARRAY_SIZE(argv), argv, CmdLineMode::Headless), (int)CommandLineParseResult::Error);
|
||||
}
|
||||
}
|
||||
// Test GL version override
|
||||
{
|
||||
const char *argv[] = {
|
||||
|
||||
Reference in new issue
Block a user