[XAM] Fixed crash related to incorrect buffer size in UserPlaylist enum

- Replaced unk_ptr in XMP_CREATE_USER_PLAYLIST_ENUMERATOR
- Simplified logic in achievements StringBuffer
This commit is contained in:
Gliniak
2026-01-07 20:10:27 +01:00
committed by Radosław Gliński
parent 4b73839bf1
commit dce4d38c0a
6 changed files with 32 additions and 37 deletions

View File

@@ -69,7 +69,8 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
reinterpret_cast<uint8_t*>(&cross_title_data); reinterpret_cast<uint8_t*>(&cross_title_data);
uint32_t item_count = 0; uint32_t item_count = 0;
X_RESULT result = e->WriteItems(0, cross_title_data_ptr, &item_count); X_RESULT result = e->WriteItems(cross_title_data_ptr,
data_ptr->buffer_size, &item_count);
XCONTENT_DATA_INTERNAL* content_data_ptr = XCONTENT_DATA_INTERNAL* content_data_ptr =
memory_->TranslateVirtual<XCONTENT_DATA_INTERNAL*>( memory_->TranslateVirtual<XCONTENT_DATA_INTERNAL*>(

View File

@@ -403,7 +403,7 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
XELOGD("XMPCreateUserPlaylistEnumerator({:08X}, {:08X}, {:08X})", XELOGD("XMPCreateUserPlaylistEnumerator({:08X}, {:08X}, {:08X})",
uint32_t(args->xmp_client), uint32_t(args->flags), uint32_t(args->xmp_client), uint32_t(args->flags),
uint32_t(args->unk_ptr)); uint32_t(args->object_ptr));
return X_E_SUCCESS; return X_E_SUCCESS;
} }
case 0x00070029: { case 0x00070029: {

View File

@@ -133,7 +133,7 @@ static_assert_size(XMP_GET_PLAYBACK_CONTROLLER, 0xC);
struct XMP_CREATE_USER_PLAYLIST_ENUMERATOR { struct XMP_CREATE_USER_PLAYLIST_ENUMERATOR {
xe::be<uint32_t> xmp_client; xe::be<uint32_t> xmp_client;
xe::be<uint32_t> flags; xe::be<uint32_t> flags;
xe::be<uint32_t> unk_ptr; xe::be<uint32_t> object_ptr;
}; };
static_assert_size(XMP_CREATE_USER_PLAYLIST_ENUMERATOR, 0xC); static_assert_size(XMP_CREATE_USER_PLAYLIST_ENUMERATOR, 0xC);

View File

@@ -30,15 +30,15 @@ uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr,
return X_ERROR_INVALID_HANDLE; return X_ERROR_INVALID_HANDLE;
} }
auto run = [e, buffer_ptr, overlapped_ptr](uint32_t& extended_error, auto run = [e, buffer_ptr, buffer_size, overlapped_ptr](
uint32_t& length) -> X_RESULT { uint32_t& extended_error, uint32_t& length) -> X_RESULT {
X_RESULT result; X_RESULT result;
uint32_t item_count = 0; uint32_t item_count = 0;
if (!buffer_ptr) { if (!buffer_ptr) {
result = X_ERROR_INVALID_PARAMETER; result = X_ERROR_INVALID_PARAMETER;
} else { } else {
result = e->WriteItems(buffer_ptr.guest_address(), result =
buffer_ptr.as<uint8_t*>(), &item_count); e->WriteItems(buffer_ptr.as<uint8_t*>(), buffer_size, &item_count);
} }
extended_error = X_HRESULT_FROM_WIN32(result); extended_error = X_HRESULT_FROM_WIN32(result);
length = item_count; length = item_count;

View File

@@ -59,8 +59,8 @@ uint8_t* XStaticUntypedEnumerator::AppendItem() {
return const_cast<uint8_t*>(&buffer_.data()[offset]); return const_cast<uint8_t*>(&buffer_.data()[offset]);
} }
uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr, uint32_t XStaticUntypedEnumerator::WriteItems(uint8_t* buffer_data,
uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) { uint32_t* written_count) {
size_t count = std::min(item_count_ - current_item_, items_per_enumerate()); size_t count = std::min(item_count_ - current_item_, items_per_enumerate());
if (!count) { if (!count) {
@@ -80,8 +80,8 @@ uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr,
return X_ERROR_SUCCESS; return X_ERROR_SUCCESS;
} }
uint32_t XAchievementEnumerator::WriteItems(uint32_t buffer_ptr, uint32_t XAchievementEnumerator::WriteItems(uint8_t* buffer_data,
uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) { uint32_t* written_count) {
size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); size_t count = std::min(items_.size() - current_item_, items_per_enumerate());
if (!count) { if (!count) {
@@ -94,10 +94,9 @@ uint32_t XAchievementEnumerator::WriteItems(uint32_t buffer_ptr,
size_t string_offset = size_t string_offset =
items_per_enumerate() * sizeof(xam::X_ACHIEVEMENT_DETAILS); items_per_enumerate() * sizeof(xam::X_ACHIEVEMENT_DETAILS);
auto string_buffer = auto string_buffer =
StringBuffer{buffer_ptr + static_cast<uint32_t>(string_offset), StringBuffer{&buffer_data[string_offset],
&buffer_data[string_offset],
count * xam::X_ACHIEVEMENT_DETAILS::kStringBufferSize}; count * xam::X_ACHIEVEMENT_DETAILS::kStringBufferSize};
for (size_t i = 0, o = current_item_; i < count; ++i, ++current_item_) { for (size_t i = 0; i < count; ++i, ++current_item_) {
const auto& item = items_[current_item_]; const auto& item = items_[current_item_];
details[i].id = item.id; details[i].id = item.id;
details[i].label_ptr = details[i].label_ptr =
@@ -120,7 +119,8 @@ uint32_t XAchievementEnumerator::WriteItems(uint32_t buffer_ptr,
return X_ERROR_SUCCESS; return X_ERROR_SUCCESS;
} }
uint32_t XTitleEnumerator::WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, uint32_t XTitleEnumerator::WriteItems(uint8_t* buffer_data,
uint32_t buffer_size,
uint32_t* written_count) { uint32_t* written_count) {
size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); size_t count = std::min(items_.size() - current_item_, items_per_enumerate());
if (!count) { if (!count) {
@@ -130,7 +130,7 @@ uint32_t XTitleEnumerator::WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
size_t size = count * item_size(); size_t size = count * item_size();
auto details = reinterpret_cast<XTITLE_PLAYED*>(buffer_data); auto details = reinterpret_cast<XTITLE_PLAYED*>(buffer_data);
for (size_t i = 0, o = current_item_; i < count; ++i, ++current_item_) { for (size_t i = 0; i < count; ++i, ++current_item_) {
const auto& item = items_[current_item_]; const auto& item = items_[current_item_];
details[i].base.title_id = item.id; details[i].base.title_id = item.id;
details[i].base.achievements_count = item.achievements_count; details[i].base.achievements_count = item.achievements_count;
@@ -164,8 +164,8 @@ uint32_t XTitleEnumerator::WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
return X_ERROR_SUCCESS; return X_ERROR_SUCCESS;
} }
uint32_t XUserStatsEnumerator::WriteItems(uint32_t buffer_ptr, uint32_t XUserStatsEnumerator::WriteItems(uint8_t* buffer_data,
uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) { uint32_t* written_count) {
size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); size_t count = std::min(items_.size() - current_item_, items_per_enumerate());
if (!count) { if (!count) {
@@ -177,11 +177,11 @@ uint32_t XUserStatsEnumerator::WriteItems(uint32_t buffer_ptr,
return X_ERROR_SUCCESS; return X_ERROR_SUCCESS;
} }
uint32_t XMPCreateUserPlaylistEnumerator::WriteItems(uint32_t buffer_ptr, uint32_t XMPCreateUserPlaylistEnumerator::WriteItems(uint8_t* buffer_data,
uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) { uint32_t* written_count) {
// Fixed 545408C0 freezing at main menu. // Fixed 545408C0 freezing at main menu.
std::memset(buffer_data, 0, extra_size()); std::memset(buffer_data, 0, buffer_size);
size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); size_t count = std::min(items_.size() - current_item_, items_per_enumerate());
if (!count) { if (!count) {
@@ -191,10 +191,7 @@ uint32_t XMPCreateUserPlaylistEnumerator::WriteItems(uint32_t buffer_ptr,
xam::XMP_USER_PLAYLIST_INFO* results = xam::XMP_USER_PLAYLIST_INFO* results =
reinterpret_cast<xam::XMP_USER_PLAYLIST_INFO*>(buffer_data); reinterpret_cast<xam::XMP_USER_PLAYLIST_INFO*>(buffer_data);
for (size_t i = 0, o = current_item_; i < count; ++i, ++current_item_) { std::copy_n(items_.begin() + current_item_, count, results);
const auto& item = items_[current_item_];
results[i] = item;
}
if (written_count) { if (written_count) {
*written_count = static_cast<uint32_t>(count); *written_count = static_cast<uint32_t>(count);

View File

@@ -85,7 +85,7 @@ class XEnumerator : public XObject {
return result; return result;
} }
virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, virtual uint32_t WriteItems(uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) = 0; uint32_t* written_count) = 0;
size_t item_size() const { return item_size_; } size_t item_size() const { return item_size_; }
@@ -110,7 +110,7 @@ class XStaticUntypedEnumerator : public XEnumerator {
uint8_t* AppendItem(); uint8_t* AppendItem();
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, uint32_t WriteItems(uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) override; uint32_t* written_count) override;
private: private:
@@ -151,30 +151,27 @@ class XAchievementEnumerator : public XEnumerator {
items_.push_back(std::move(item)); items_.push_back(std::move(item));
} }
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, uint32_t WriteItems(uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) override; uint32_t* written_count) override;
private: private:
struct StringBuffer { struct StringBuffer {
uint32_t ptr;
uint8_t* data; uint8_t* data;
size_t remaining_bytes; size_t remaining_bytes;
}; };
uint32_t AppendString(StringBuffer& sb, const std::u16string_view string) { uint32_t AppendString(StringBuffer& sb, const std::u16string_view string) {
size_t count = string.length() + 1; const size_t count = string.length() + 1;
size_t size = count * sizeof(char16_t); const size_t size = count * sizeof(char16_t);
if (size > sb.remaining_bytes) { if (size > sb.remaining_bytes) {
assert_always(); assert_always();
return 0; return 0;
} }
auto ptr = sb.ptr;
string_util::copy_and_swap_truncating(reinterpret_cast<char16_t*>(sb.data), string_util::copy_and_swap_truncating(reinterpret_cast<char16_t*>(sb.data),
string, count); string, count);
sb.ptr += static_cast<uint32_t>(size);
sb.data += size; sb.data += size;
sb.remaining_bytes -= size; sb.remaining_bytes -= size;
return ptr; return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(sb.data - size));
} }
private: private:
@@ -195,7 +192,7 @@ class XTitleEnumerator : public XEnumerator {
void AppendItem(const xam::TitleInfo& item) { items_.push_back(item); } void AppendItem(const xam::TitleInfo& item) { items_.push_back(item); }
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, uint32_t WriteItems(uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) override; uint32_t* written_count) override;
private: private:
@@ -214,7 +211,7 @@ class XUserStatsEnumerator : public XEnumerator {
XUserStatsEnumerator(KernelState* kernel_state, size_t items_per_enumerate) XUserStatsEnumerator(KernelState* kernel_state, size_t items_per_enumerate)
: XEnumerator(kernel_state, items_per_enumerate, 0) {} : XEnumerator(kernel_state, items_per_enumerate, 0) {}
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, uint32_t WriteItems(uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) override; uint32_t* written_count) override;
private: private:
@@ -234,7 +231,7 @@ class XMPCreateUserPlaylistEnumerator : public XEnumerator {
items_.push_back(item); items_.push_back(item);
} }
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, uint32_t WriteItems(uint8_t* buffer_data, uint32_t buffer_size,
uint32_t* written_count) override; uint32_t* written_count) override;
private: private: