Files
ppsspp/Core/HLE/sceSfmt19937.cpp
Henrik RydgårdandClaude Opus 5.5 3880999ada Misc HLE: Fix heap leak, USB waits, RNG indices and small races
- sceHeapDeleteHeap never freed the heap's memory. Allocation failure
  returned -1 rather than a null pointer, and a near-4GB size wrapped.
- The USB wait timeout resumed threads that were no longer waiting on
  USB, and UsbUpdateState resumed them too, and never rescheduled.
- The Mersenne Twister drew from mt_[index_] with the index taken from
  guest memory. It's now taken modulo the state size. sceSfmt19937
  checks its index, and that fill arrays are at least a state long,
  which the library writes regardless of the length it's given.
- sceCccEncodeUTF16's surrogate test also caught U+F800 - U+FFFF, which
  includes the fullwidth forms.
- sceAudioRoutingSetVolumeMode stored the routing mode.
- A sample rate of 0 to sceAudioInput or the camera mic divided by zero,
  and a huge sample count sized a host buffer. sceP3daBridgeCore's sizes
  could wrap. sceRtc's tz offset could overflow tm_min.
- Camera shutdown freed the frame buffer and config without the lock
  the capture thread uses. GPS data is set from the platform's location
  thread, so it's now locked too, and the satellite index is bounded.
- A loop in the sys event handler list hung the unregister.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-27 10:39:45 +01:00

132 lines
5.1 KiB
C++

// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// Mersenne Twister random number generator module.
#define SFMT_MEXP 19937
#include "ext/sfmt19937/SFMT.h"
#include "Common/Log.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceSfmt19937.h"
// The library indexes its state with idx, which lives in game memory.
static bool ValidSfmtIndex(u32 sfmt) {
const sfmt_t *psfmt = (const sfmt_t *)Memory::GetPointerUnchecked(sfmt);
return psfmt->idx >= 0 && psfmt->idx <= SFMT_N32;
}
static int sceSfmt19937InitGenRand(u32 sfmt, u32 seed) {
if (!Memory::IsValidAddress(sfmt)) {
ERROR_LOG(Log::HLE, "sceSfmt19937InitGenRand(sfmt=%08x, seed=%08x) - bad address(es)", sfmt, seed);
return -1;
}
INFO_LOG(Log::HLE, "sceSfmt19937InitGenRand(sfmt=%08x, seed=%08x)", sfmt, seed);
sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt);
sfmt_init_gen_rand(psfmt, seed);
return 0;
}
static int sceSfmt19937InitByArray(u32 sfmt, u32 seeds, int seedslen) {
if (!Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(seeds) || !Memory::IsValidAddress(seeds + 4 * (seedslen - 1))) {
ERROR_LOG(Log::HLE, "sceSfmt19937InitByArray(sfmt=%08x, seeds=%08x, seedslen=%08x) - bad address(es)", sfmt, seeds, seedslen);
return -1;
}
INFO_LOG(Log::HLE, "sceSfmt19937InitByArray(sfmt=%08x, seeds=%08x, seedslen=%08x)", sfmt, seeds, seedslen);
sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt);
uint32_t *pseeds = (uint32_t *)Memory::GetPointerUnchecked(seeds);
sfmt_init_by_array(psfmt, pseeds, seedslen);
return 0;
}
static u32 sceSfmt19937GenRand32(u32 sfmt) {
if (!Memory::IsValidAddress(sfmt) || !ValidSfmtIndex(sfmt)) {
ERROR_LOG(Log::HLE, "sceSfmt19937GenRand32(sfmt=%08x) - bad address(es)", sfmt);
return -1;
}
INFO_LOG(Log::HLE, "sceSfmt19937GenRand32(sfmt=%08x)", sfmt);
sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt);
u32 ret = sfmt_genrand_uint32(psfmt);
return ret;
}
static u64 sceSfmt19937GenRand64(u32 sfmt) {
if (!Memory::IsValidAddress(sfmt) || !ValidSfmtIndex(sfmt)) {
ERROR_LOG(Log::HLE, "sceSfmt19937GenRand64(sfmt=%08x) - bad address(es)", sfmt);
return -1;
}
INFO_LOG(Log::HLE, "sceSfmt19937GenRand64(sfmt=%08x)", sfmt);
sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt);
u64 ret = sfmt_genrand_uint64(psfmt);
return ret;
}
static int sceSfmt19937FillArray32(u32 sfmt, u32 array, int arraylen) {
// The library fills whole blocks, and needs at least a state's worth of them.
if (arraylen < SFMT_N32 || (arraylen % 4) != 0 || !Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 4 * (arraylen - 1))) {
ERROR_LOG(Log::HLE, "sceSfmt19937FillArray32(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen);
return -1;
}
INFO_LOG(Log::HLE, "sceSfmt19937FillArray32(sfmt=%08x, ar=%08x, arlen=%08x)", sfmt, array, arraylen);
sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt);
uint32_t *parray = (uint32_t *)Memory::GetPointerUnchecked(array);
sfmt_fill_array32(psfmt, parray, arraylen);
return 0;
}
static int sceSfmt19937FillArray64(u32 sfmt, u32 array, int arraylen) {
// The library fills whole blocks, and needs at least a state's worth of them.
if (arraylen < SFMT_N64 || (arraylen % 2) != 0 || !Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 8 * (arraylen - 1))) {
ERROR_LOG(Log::HLE, "sceSfmt19937FillArray64(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen);
return -1;
}
INFO_LOG(Log::HLE, "sceSfmt19937FillArray64(sfmt=%08x, ar=%08x, arlen=%08x)", sfmt, array, arraylen);
sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt);
uint64_t *parray = (uint64_t *)Memory::GetPointerUnchecked(array);
sfmt_fill_array64(psfmt, parray, arraylen);
return 0;
}
const HLEFunction sceSfmt19937[] =
{
{0X161ACEB2, &WrapI_UU<sceSfmt19937InitGenRand>, "sceSfmt19937InitGenRand", 'i', "xx" },
{0XDD5A5D6C, &WrapI_UUI<sceSfmt19937InitByArray>, "sceSfmt19937InitByArray", 'i', "xxi"},
{0XB33FE749, &WrapU_U<sceSfmt19937GenRand32>, "sceSfmt19937GenRand32", 'x', "x" },
{0XD5AC9F99, &WrapU64_U<sceSfmt19937GenRand64>, "sceSfmt19937GenRand64", 'X', "x" },
{0XDB025BFA, &WrapI_UUI<sceSfmt19937FillArray32>, "sceSfmt19937FillArray32", 'i', "xxi"},
{0XEE2938C4, &WrapI_UUI<sceSfmt19937FillArray64>, "sceSfmt19937FillArray64", 'i', "xxi"},
};
void Register_sceSfmt19937()
{
RegisterHLEModule("sceSfmt19937", ARRAY_SIZE(sceSfmt19937), sceSfmt19937);
}