mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-01 18:40:57 -06:00
Fix startup crash on malformed patch indexes and short CONTENT_ID
Prevents early startup termination triggered by `CUSA03173` when auto-patch repositories contain missing/unreadable/malformed `files.json` by adding open checks, JSON parse exception handling, and basic schema validation. Hardens `param.sfo` handling by guarding `CONTENT_ID` substring extraction and falling back to `TITLE_ID` , and by catching invalid `sdk_ver` parsing from `PUBTOOLINFO` with a safe fallback to firmware version. PS: Now it has Clang formating that @georgemorallis asked for, also remove exceptions for Pubtoolinfo and added logging for all cases for `CONTENT_ID`
This commit is contained in:
parent
bb9c223d42
commit
729e1f0328
@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <pugixml.hpp>
|
||||
#include "common/config.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
@ -193,16 +194,56 @@ void OnGameLoaded() {
|
||||
ApplyPatchesFromXML(file_path);
|
||||
}
|
||||
} else if (EmulatorState::GetInstance()->IsAutoPatchesLoadEnabled()) {
|
||||
if (g_game_serial.empty()) {
|
||||
ApplyPendingPatches();
|
||||
return;
|
||||
}
|
||||
for (auto const& repo : std::filesystem::directory_iterator(patch_dir)) {
|
||||
if (!repo.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
std::ifstream json_file{repo.path() / "files.json"};
|
||||
nlohmann::json available_patches = nlohmann::json::parse(json_file);
|
||||
const auto json_path = repo.path() / "files.json";
|
||||
if (!std::filesystem::exists(json_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ifstream json_file{json_path};
|
||||
if (!json_file.is_open()) {
|
||||
LOG_ERROR(Loader, "Failed to open patch index: {}", json_path.string());
|
||||
continue;
|
||||
}
|
||||
|
||||
nlohmann::json available_patches;
|
||||
try {
|
||||
available_patches = nlohmann::json::parse(json_file);
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(Loader, "Failed to parse patch index {}: {}", json_path.string(),
|
||||
e.what());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!available_patches.is_object()) {
|
||||
LOG_ERROR(Loader, "Invalid patch index (expected object): {}", json_path.string());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::filesystem::path game_patch_file;
|
||||
for (auto const& [filename, serials] : available_patches.items()) {
|
||||
if (std::find(serials.begin(), serials.end(), g_game_serial) != serials.end()) {
|
||||
game_patch_file = repo.path() / filename;
|
||||
for (auto it = available_patches.begin(); it != available_patches.end(); ++it) {
|
||||
const auto& serials = it.value();
|
||||
if (!serials.is_array()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool matches = false;
|
||||
for (const auto& serial : serials) {
|
||||
if (serial.is_string() &&
|
||||
serial.get_ref<const std::string&>() == g_game_serial) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
game_patch_file = repo.path() / it.key();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <charconv>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@ -132,7 +133,7 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
|
||||
std::string id;
|
||||
std::string title;
|
||||
std::string app_version;
|
||||
u32 sdk_version;
|
||||
u32 sdk_version{};
|
||||
u32 fw_version;
|
||||
Common::PSFAttributes psf_attributes{};
|
||||
if (param_sfo_exists) {
|
||||
@ -141,10 +142,17 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
|
||||
|
||||
const auto content_id = param_sfo->GetString("CONTENT_ID");
|
||||
const auto title_id = param_sfo->GetString("TITLE_ID");
|
||||
if (content_id.has_value() && !content_id->empty()) {
|
||||
id = std::string(*content_id, 7, 9);
|
||||
} else if (title_id.has_value()) {
|
||||
id = *title_id;
|
||||
if (content_id.has_value() && content_id->size() >= 16) {
|
||||
id = content_id->substr(7, 9);
|
||||
} else {
|
||||
if (content_id.has_value()) {
|
||||
LOG_WARNING(Loader, "CONTENT_ID too short to derive game id: {}", *content_id);
|
||||
} else {
|
||||
LOG_WARNING(Loader, "CONTENT_ID is missing");
|
||||
}
|
||||
if (title_id.has_value() && !title_id->empty()) {
|
||||
id = *title_id;
|
||||
}
|
||||
}
|
||||
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
||||
fw_version = param_sfo->GetInteger("SYSTEM_VER").value_or(0x4700000);
|
||||
@ -164,16 +172,28 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
|
||||
} else {
|
||||
// Increment offset to account for sdk_ver= part of string.
|
||||
sdk_ver_offset += 8;
|
||||
u64 sdk_ver_len = pubtool_info.find(",", sdk_ver_offset);
|
||||
if (sdk_ver_len == pubtool_info.npos) {
|
||||
// If there's no more commas, this is likely the last entry of pubtool info.
|
||||
// Use string length instead.
|
||||
sdk_ver_len = pubtool_info.size();
|
||||
if (sdk_ver_offset > pubtool_info.size()) {
|
||||
LOG_WARNING(Loader, "PUBTOOLINFO sdk_ver is malformed");
|
||||
sdk_version = fw_version;
|
||||
} else {
|
||||
u64 sdk_ver_len = pubtool_info.find(",", sdk_ver_offset);
|
||||
if (sdk_ver_len == pubtool_info.npos) {
|
||||
// If there's no more commas, this is likely the last entry of pubtool info.
|
||||
// Use string length instead.
|
||||
sdk_ver_len = pubtool_info.size();
|
||||
}
|
||||
sdk_ver_len -= sdk_ver_offset;
|
||||
std::string_view sdk_ver_string = pubtool_info.substr(sdk_ver_offset, sdk_ver_len);
|
||||
// Number is stored in base 16.
|
||||
auto result =
|
||||
std::from_chars(sdk_ver_string.data(),
|
||||
sdk_ver_string.data() + sdk_ver_string.size(), sdk_version, 16);
|
||||
if (result.ec != std::errc()) {
|
||||
LOG_WARNING(Loader, "Failed to parse sdk_ver '{}' from PUBTOOLINFO",
|
||||
sdk_ver_string);
|
||||
sdk_version = fw_version;
|
||||
}
|
||||
}
|
||||
sdk_ver_len -= sdk_ver_offset;
|
||||
std::string sdk_ver_string = pubtool_info.substr(sdk_ver_offset, sdk_ver_len).data();
|
||||
// Number is stored in base 16.
|
||||
sdk_version = std::stoi(sdk_ver_string, nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user