Files
AnyPS5/core/libs/tests/GuestSystemConfiguration.cpp
T
milescovielloandClaude Opus 5.5 ea0b9c1272 fix(libkernel): zero vm.loadavg's padding and clamp the scaled averages
GuestLoadAverage's braced initializer left its four bytes of padding after ldavg indeterminate, and the sysctl copies all 24 bytes to the guest. The scaled value of a load over UINT32_MAX / 2048 was converted out of range. The test now checks the padding and the exact fscale 2048 scaling against the host averages read just before and after the call.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 20:32:29 +00:00

1203 lines
60 KiB
C++

#include "prx/libkernel/include/Api.hpp"
#include "prx/libkernel/Time/include/Time.hpp"
#include "prx/libc/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libkernel/KernelErrors.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <stdexcept>
#include <string>
#include <vector>
static_assert(offsetof(SceKernelSystemSwVersion, size) == 0x00);
static_assert(offsetof(SceKernelSystemSwVersion, versionString) == 0x08);
static_assert(offsetof(SceKernelSystemSwVersion, version) == 0x24);
static_assert(sizeof(SceKernelSystemSwVersion) == 0x28);
extern "C" {
extern char** environ_nid_postfix;
}
static void Require(bool value) { if (!value) std::abort(); }
static void CheckProcessorCountSysctl() {
const int mib[] = {6, 3};
const int processors = static_cast<int>(sysconf_nid_postfix(58));
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(int));
int value = 0;
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, nullptr, 0) == 0 && value == processors && length == sizeof(int));
value = 0;
length = 16;
Require(sysctlbyname_nid_postfix("hw.ncpu", &value, &length, nullptr, 0) == 0 && value == processors && length == sizeof(int));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[4] = {0xaa, 0xaa, 0xaa, 0xaa};
length = 2;
Require(sysctlbyname_nid_postfix("hw.ncpu", bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 2 && bytes[2] == 0xaa && bytes[3] == 0xaa);
Require(sysctl_nid_postfix(mib, 2, bytes, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
Require(sysctl_nid_postfix(mib, 1, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(sysctl_nid_postfix(mib, 25, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(sysctl_nid_postfix(nullptr, 2, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 14);
Require(sysctlbyname_nid_postfix(nullptr, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 14);
bool threw = false;
const int unknown[] = {6, 99};
try {
sysctl_nid_postfix(unknown, 2, &value, &length, nullptr, 0);
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
}
static void CheckPageSizeSysctl() {
const int mib[] = {6, 7};
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(int));
int value = 0;
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, nullptr, 0) == 0 && value == 0x4000 && length == sizeof(int));
value = 0;
length = 16;
Require(sysctlbyname_nid_postfix("hw.pagesize", &value, &length, nullptr, 0) == 0 && value == 0x4000 && length == sizeof(int));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[4] = {0xaa, 0xaa, 0xaa, 0xaa};
length = 2;
Require(sysctlbyname_nid_postfix("hw.pagesize", bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 2 && bytes[2] == 0xaa && bytes[3] == 0xaa);
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
Require(sysctlbyname_nid_postfix("hw.pagesize", &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckPhysicalMemorySysctl(int number, const char* name) {
const int mib[] = {6, number};
const std::uint64_t expected = static_cast<std::uint64_t>(sysconf_nid_postfix(121)) * 0x4000;
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(std::uint64_t));
std::uint64_t value = 0;
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, nullptr, 0) == 0 && value == expected && length == sizeof(std::uint64_t));
value = 0;
length = 16;
Require(sysctlbyname_nid_postfix(name, &value, &length, nullptr, 0) == 0 && value == expected && length == sizeof(std::uint64_t));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[8] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
length = 4;
Require(sysctlbyname_nid_postfix(name, bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 4 && bytes[4] == 0xaa);
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
Require(sysctlbyname_nid_postfix(name, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckModelSysctl() {
const int mib[] = {6, 2};
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length > 1);
const std::size_t size = length;
char model[128] = {};
length = sizeof(model);
Require(sysctlbyname_nid_postfix("hw.model", model, &length, nullptr, 0) == 0 && length == size);
Require(std::strlen(model) + 1 == size && model[0] != ' ');
Require(*__error_nid_postfix() == 13);
char truncated[4] = {};
length = sizeof(truncated);
Require(sysctl_nid_postfix(mib, 2, truncated, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == sizeof(truncated) && std::memcmp(truncated, model, sizeof(truncated)) == 0);
length = sizeof(model);
Require(sysctlbyname_nid_postfix("hw.model", model, &length, model, size) == -1 && *__error_nid_postfix() == 1);
}
static void CheckTscFrequencySysctl() {
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctlbyname_nid_postfix("machdep.tsc_freq", nullptr, &length, nullptr, 0) == 0 && length == sizeof(std::uint64_t));
std::uint64_t value = 0;
length = sizeof(value);
Require(sysctlbyname_nid_postfix("machdep.tsc_freq", &value, &length, nullptr, 0) == 0);
Require(value == sceKernelGetTscFrequency() && value != 0 && length == sizeof(value));
Require(*__error_nid_postfix() == 13);
std::uint32_t truncated = 0;
length = sizeof(truncated);
Require(sysctlbyname_nid_postfix("machdep.tsc_freq", &truncated, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
length = sizeof(value);
Require(sysctlbyname_nid_postfix("machdep.tsc_freq", &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
}
static bool Untouched(const unsigned char* bytes, std::size_t size) {
for (std::size_t i = 0; i < size; ++i)
if (bytes[i] != 0xaa) return false;
return true;
}
template <typename TCall>
static bool Throws(TCall call) {
try {
call();
} catch (const std::runtime_error&) {
return true;
}
return false;
}
static void CheckUnansweredSysctl() {
static constexpr const char* names[] = {
"hw.byteorder",
"hw.cacheline_size",
"hw.floatingpoint",
"hw.machine_arch",
"hw.usermem",
"kern.bootfile",
"kern.clockrate",
"kern.cp_time",
"kern.ident",
"kern.maxfiles",
"kern.maxfilesperproc",
"kern.maxproc",
"kern.ps_strings",
"kern.sched.name",
"kern.smp.maxcpus",
"kern.stackprot",
"kern.timecounter.hardware",
"machdep.cacheline_size",
};
unsigned char buffer[64];
for (const char* name : names) {
std::memset(buffer, 0xaa, sizeof(buffer));
std::size_t length = sizeof(buffer);
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(name, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
Require(length == sizeof(buffer) && Untouched(buffer, sizeof(buffer)));
length = 77;
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(name, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2 && length == 77);
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(name, buffer, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
Require(Untouched(buffer, sizeof(buffer)));
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(name, nullptr, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
if (std::strcmp(name, "machdep.cacheline_size") == 0) continue;
length = sizeof(buffer);
Require(Throws([&] { sysctlbyname_nid_postfix(name, buffer, &length, buffer, sizeof(buffer)); }));
}
struct Numbered {
const char* name;
int mib[2];
};
static constexpr Numbered numbered[] = {
{"hw.byteorder", {6, 4}},
{"hw.machine_arch", {6, 11}},
{"kern.clockrate", {1, 12}},
{"kern.maxfiles", {1, 7}},
{"kern.maxfilesperproc", {1, 27}},
{"kern.maxproc", {1, 6}},
{"kern.ps_strings", {1, 32}},
};
for (const auto& entry : numbered) {
int mib[4] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t size = 4;
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix(entry.name, mib, &size) == 0 && size == 2);
Require(mib[0] == entry.mib[0] && mib[1] == entry.mib[1] && mib[2] == 0x5a5a5a5a);
Require(*__error_nid_postfix() == 13);
std::memset(buffer, 0xaa, sizeof(buffer));
std::size_t length = sizeof(buffer);
Require(sysctl_nid_postfix(mib, 2, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
Require(length == sizeof(buffer) && Untouched(buffer, sizeof(buffer)));
length = 77;
*__error_nid_postfix() = 13;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2 && length == 77);
*__error_nid_postfix() = 13;
Require(sysctl_nid_postfix(mib, 2, buffer, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 2 && Untouched(buffer, sizeof(buffer)));
*__error_nid_postfix() = 13;
Require(sysctl_nid_postfix(mib, 2, nullptr, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
length = sizeof(buffer);
Require(Throws([&] { sysctl_nid_postfix(mib, 2, buffer, &length, buffer, sizeof(buffer)); }));
}
int mib[4] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t size = 0;
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix("kern.maxproc", nullptr, &size) == 0 && size == 2 && *__error_nid_postfix() == 13);
size = 1;
Require(sysctlnametomib_nid_postfix("kern.maxproc", mib, &size) == -1 && *__error_nid_postfix() == 12);
Require(size == 1 && mib[0] == 1 && mib[1] == 0x5a5a5a5a);
mib[0] = 0x5a5a5a5a;
size = 0;
Require(sysctlnametomib_nid_postfix("kern.maxproc", mib, &size) == -1 && *__error_nid_postfix() == 12);
Require(size == 0 && mib[0] == 0x5a5a5a5a);
static constexpr const char* unresolved[] = {"hw.cacheline_size", "hw.usermem", "machdep.cacheline_size"};
for (const char* name : unresolved) {
int untouched[4] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
size = 4;
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix(name, untouched, &size) == -1 && *__error_nid_postfix() == 2);
Require(size == 4 && untouched[0] == 0x5a5a5a5a && untouched[1] == 0x5a5a5a5a && untouched[2] == 0x5a5a5a5a);
}
}
static void CheckUnknownSysctlName() {
static constexpr const char* name = "kern.anyps5_no_such_name";
unsigned char buffer[16];
std::memset(buffer, 0xaa, sizeof(buffer));
std::size_t length = sizeof(buffer);
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(name, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
Require(length == sizeof(buffer) && Untouched(buffer, sizeof(buffer)));
length = 77;
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(name, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2 && length == 77);
int mib[4] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t mibLength = 4;
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix(name, mib, &mibLength) == -1 && *__error_nid_postfix() == 2);
Require(mibLength == 4 && mib[0] == 0x5a5a5a5a && mib[1] == 0x5a5a5a5a && mib[2] == 0x5a5a5a5a && mib[3] == 0x5a5a5a5a);
mibLength = 0;
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix(name, nullptr, &mibLength) == -1 && *__error_nid_postfix() == 2 && mibLength == 0);
}
static void CheckPathnameSysctl() {
*__error_nid_postfix() = 13;
char buffer[32] = {};
std::size_t length = sizeof(buffer);
Require(sysctlbyname_nid_postfix("kern.proc.pathname", buffer, &length, nullptr, 0) == -1);
Require(*__error_nid_postfix() == 22);
const int mibTooShort[] = {1, 14, 12};
Require(sysctl_nid_postfix(mibTooShort, 3, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
const int mibTooLong[] = {1, 14, 12, -1, 0};
Require(sysctl_nid_postfix(mibTooLong, 5, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(sysctl_nid_postfix(mibTooShort, 3, buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 1);
Require(sysctl_nid_postfix(mibTooLong, 5, buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 1);
Require(sysctlbyname_nid_postfix("kern.proc.pathname", buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 1);
const int mibSelf[] = {1, 14, 12, -1};
length = 0;
Require(sysctl_nid_postfix(mibSelf, 4, nullptr, &length, nullptr, 0) == 0 && length == sizeof("/app0/eboot.bin"));
std::memset(buffer, 0xaa, sizeof(buffer));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibSelf, 4, buffer, &length, nullptr, 0) == 0);
Require(length == sizeof("/app0/eboot.bin"));
Require(std::strcmp(buffer, "/app0/eboot.bin") == 0);
const int callerPid = getpid_nid_postfix();
const int mibPid[] = {1, 14, 12, callerPid};
std::memset(buffer, 0xaa, sizeof(buffer));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibPid, 4, buffer, &length, nullptr, 0) == 0);
Require(length == sizeof("/app0/eboot.bin"));
Require(std::strcmp(buffer, "/app0/eboot.bin") == 0);
const int mibForeign[] = {1, 14, 12, callerPid + 1000};
Require(sysctl_nid_postfix(mibForeign, 4, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
length = 5;
std::memset(buffer, 0xaa, sizeof(buffer));
Require(sysctl_nid_postfix(mibSelf, 4, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 5 && buffer[4] == '0' && buffer[5] == static_cast<char>(0xaa));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibSelf, 4, buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckProcessSysctl() {
const int callerPid = getpid_nid_postfix();
const int mibPid[] = {1, 14, 1, callerPid};
std::size_t length = 0;
Require(sysctl_nid_postfix(mibPid, 4, nullptr, &length, nullptr, 0) == 0 && length == 1088);
unsigned char buffer[1100];
std::memset(buffer, 0xaa, sizeof(buffer));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibPid, 4, buffer, &length, nullptr, 0) == 0 && length == 1088);
std::int32_t structSize = 0;
std::int32_t pid = 0;
std::int32_t parentPid = 0;
std::int64_t flag = -1;
std::memcpy(&structSize, buffer, sizeof(structSize));
std::memcpy(&pid, buffer + 72, sizeof(pid));
std::memcpy(&parentPid, buffer + 76, sizeof(parentPid));
std::memcpy(&flag, buffer + 368, sizeof(flag));
Require(structSize == 1088 && pid == callerPid && parentPid == getppid_nid_postfix());
Require((flag & 0x800) == 0);
Require(std::strcmp(reinterpret_cast<const char*>(buffer + 447), "eboot.bin") == 0);
Require(buffer[4] == 0 && buffer[80] == 0 && buffer[1087] == 0 && buffer[1088] == 0xaa);
const int mibForeign[] = {1, 14, 1, callerPid + 1000};
Require(sysctl_nid_postfix(mibForeign, 4, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
const int mibSelfAlias[] = {1, 14, 1, -1};
Require(sysctl_nid_postfix(mibSelfAlias, 4, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
const int mibTooShort[] = {1, 14, 1};
Require(sysctl_nid_postfix(mibTooShort, 3, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
const int mibTooLong[] = {1, 14, 1, callerPid, 0};
Require(sysctl_nid_postfix(mibTooLong, 5, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibPid, 4, buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 1);
length = 100;
Require(sysctl_nid_postfix(mibPid, 4, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12 && length == 100);
}
struct SystemString {
int mib[2];
const char* name;
const char* value;
};
static const SystemString SystemStrings[] = {
{{1, 1}, "kern.ostype", "FreeBSD"},
{{1, 2}, "kern.osrelease", "0.0-prototype"},
{{1, 4}, "kern.version", "FreeBSD 11.4-RELEASE\n"},
{{1, 10}, "kern.hostname", ""},
{{6, 2}, "hw.model", "100-000001020 "},
{{6, 1}, "hw.machine", "amd64"},
};
static void CheckSystemStringSysctl() {
for (const auto& entry : SystemStrings) {
const std::size_t size = std::strlen(entry.value) + 1;
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(entry.mib, 2, nullptr, &length, nullptr, 0) == 0 && length == size);
char buffer[64];
std::memset(buffer, 0xaa, sizeof(buffer));
length = sizeof(buffer);
Require(sysctl_nid_postfix(entry.mib, 2, buffer, &length, nullptr, 0) == 0 && length == size);
Require(std::strcmp(buffer, entry.value) == 0 && buffer[size] == static_cast<char>(0xaa));
Require(*__error_nid_postfix() == 13);
std::memset(buffer, 0xaa, sizeof(buffer));
length = size - 1;
Require(sysctl_nid_postfix(entry.mib, 2, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == size - 1 && std::memcmp(buffer, entry.value, size - 1) == 0 && buffer[size - 1] == static_cast<char>(0xaa));
length = sizeof(buffer);
Require(sysctl_nid_postfix(entry.mib, 2, buffer, &length, "Prospero", sizeof("Prospero")) == -1 && *__error_nid_postfix() == 1);
const int deeper[] = {entry.mib[0], entry.mib[1], 0};
length = sizeof(buffer);
Require(sysctl_nid_postfix(deeper, 3, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 20);
Require(length == sizeof(buffer));
}
}
static void CheckSystemStringNames() {
for (const auto& entry : SystemStrings) {
*__error_nid_postfix() = 13;
char buffer[64];
std::memset(buffer, 0xaa, sizeof(buffer));
std::size_t length = sizeof(buffer);
Require(sysctlbyname_nid_postfix(entry.name, buffer, &length, nullptr, 0) == 0 && length == std::strlen(entry.value) + 1);
Require(std::strcmp(buffer, entry.value) == 0 && *__error_nid_postfix() == 13);
Require(sysctlbyname_nid_postfix(entry.name, buffer, &length, "Prospero", sizeof("Prospero")) == -1 && *__error_nid_postfix() == 1);
int mib[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t size = 3;
Require(sysctlnametomib_nid_postfix(entry.name, mib, &size) == 0 && size == 2);
Require(mib[0] == entry.mib[0] && mib[1] == entry.mib[1] && mib[2] == 0x5a5a5a5a);
}
}
static void CheckMeasuredIntegerSysctl() {
struct MeasuredInteger {
int mib[2];
const char* name;
std::int32_t value;
};
static constexpr MeasuredInteger integers[] = {
{{1, 3}, "kern.osrevision", 199506},
{{1, 8}, "kern.argmax", 262144},
{{1, 18}, "kern.ngroups", 1023},
};
for (const auto& entry : integers) {
std::int32_t value = 0;
std::size_t length = sizeof(value);
*__error_nid_postfix() = 13;
Require(sysctl_nid_postfix(entry.mib, 2, &value, &length, nullptr, 0) == 0 && value == entry.value && length == sizeof(value));
value = 0;
length = sizeof(value);
Require(sysctlbyname_nid_postfix(entry.name, &value, &length, nullptr, 0) == 0 && value == entry.value && *__error_nid_postfix() == 13);
length = 3;
Require(sysctlbyname_nid_postfix(entry.name, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12 && length == 3);
length = sizeof(value);
Require(sysctl_nid_postfix(entry.mib, 2, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
}
}
static void CheckOsReleaseDateSysctl() {
const int mib[] = {1, 24};
constexpr std::int32_t expected = 900000;
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(expected));
std::int32_t value = 0;
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, nullptr, 0) == 0 && value == expected && length == sizeof(value));
Require(*__error_nid_postfix() == 13);
value = 0;
length = sizeof(value);
Require(sysctlbyname_nid_postfix("kern.osreldate", &value, &length, nullptr, 0) == 0 && value == expected && length == sizeof(value));
Require(*__error_nid_postfix() == 13);
int namedMib[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t mibLength = 3;
Require(sysctlnametomib_nid_postfix("kern.osreldate", namedMib, &mibLength) == 0 && mibLength == 2);
Require(namedMib[0] == mib[0] && namedMib[1] == mib[1] && namedMib[2] == 0x5a5a5a5a);
value = 0;
length = sizeof(value);
Require(sysctl_nid_postfix(namedMib, static_cast<std::uint32_t>(mibLength), &value, &length, nullptr, 0) == 0 && value == expected);
unsigned char truncated[4] = {0xaa, 0xaa, 0xaa, 0xaa};
length = 2;
Require(sysctlbyname_nid_postfix("kern.osreldate", truncated, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 2 && truncated[0] == static_cast<unsigned char>(expected) && truncated[1] == static_cast<unsigned char>(expected >> 8) && truncated[2] == 0xaa && truncated[3] == 0xaa);
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
Require(sysctlbyname_nid_postfix("kern.osreldate", &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
const int deeper[] = {1, 24, 0};
length = sizeof(value);
Require(sysctl_nid_postfix(deeper, 3, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 20);
}
struct BootTimeval {
std::int64_t tv_sec;
std::int64_t tv_usec;
};
static_assert(sizeof(BootTimeval) == 16);
static void CheckBootTimeSysctl() {
const int mib[] = {1, 21};
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(BootTimeval));
length = 0;
Require(sysctlbyname_nid_postfix("kern.boottime", nullptr, &length, nullptr, 0) == 0 && length == sizeof(BootTimeval));
BootTimeval first{};
length = sizeof(first);
Require(sysctl_nid_postfix(mib, 2, &first, &length, nullptr, 0) == 0 && length == sizeof(first));
Require(first.tv_sec > 0 && first.tv_sec <= static_cast<std::int64_t>(std::time(nullptr)));
Require(first.tv_usec >= 0 && first.tv_usec < 1000000);
KernelTimespec now{};
KernelTimespec uptime{};
Require(clock_gettime_nid_postfix(5, &uptime) == 0 && clock_gettime_nid_postfix(0, &now) == 0);
const std::int64_t drift = (first.tv_sec + uptime.tv_sec - now.tv_sec) * 1000000 + first.tv_usec + uptime.tv_nsec / 1000 - now.tv_nsec / 1000;
Require(drift > -1000000 && drift < 1000000);
BootTimeval second{};
length = sizeof(second);
Require(sysctl_nid_postfix(mib, 2, &second, &length, nullptr, 0) == 0 && length == sizeof(second));
Require(second.tv_sec == first.tv_sec && second.tv_usec == first.tv_usec);
BootTimeval named{};
length = 32;
Require(sysctlbyname_nid_postfix("kern.boottime", &named, &length, nullptr, 0) == 0 && length == sizeof(named));
Require(named.tv_sec == first.tv_sec && named.tv_usec == first.tv_usec);
Require(*__error_nid_postfix() == 13);
int namedMib[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t mibLength = 3;
Require(sysctlnametomib_nid_postfix("kern.boottime", namedMib, &mibLength) == 0 && mibLength == 2);
Require(namedMib[0] == 1 && namedMib[1] == 21 && namedMib[2] == 0x5a5a5a5a);
unsigned char truncated[16];
std::memset(truncated, 0xaa, sizeof(truncated));
length = 8;
Require(sysctl_nid_postfix(mib, 2, truncated, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 8 && std::memcmp(truncated, &first.tv_sec, 8) == 0 && truncated[8] == 0xaa);
std::memset(truncated, 0xaa, sizeof(truncated));
length = 8;
Require(sysctlbyname_nid_postfix("kern.boottime", truncated, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 8 && truncated[8] == 0xaa);
length = sizeof(first);
Require(sysctl_nid_postfix(mib, 2, &first, &length, &first, sizeof(first)) == -1 && *__error_nid_postfix() == 1);
Require(sysctlbyname_nid_postfix("kern.boottime", &first, &length, &first, sizeof(first)) == -1 && *__error_nid_postfix() == 1);
}
struct LoadAverage {
std::uint32_t ldavg[3];
std::int64_t fscale;
};
static_assert(sizeof(LoadAverage) == 24);
static void CheckLoadAverageSysctl() {
const int mib[] = {2, 2};
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(LoadAverage));
length = 0;
Require(sysctlbyname_nid_postfix("vm.loadavg", nullptr, &length, nullptr, 0) == 0 && length == sizeof(LoadAverage));
LoadAverage load;
std::memset(&load, 0xaa, sizeof(load));
length = sizeof(load);
#ifndef _WIN32
double before[3]{};
Require(getloadavg(before, 3) == 3);
#endif
Require(sysctl_nid_postfix(mib, 2, &load, &length, nullptr, 0) == 0 && length == sizeof(load) && load.fscale == 2048);
std::uint8_t padding[4];
std::memcpy(padding, reinterpret_cast<const std::uint8_t*>(&load) + 12, sizeof(padding));
Require(padding[0] == 0 && padding[1] == 0 && padding[2] == 0 && padding[3] == 0);
#ifndef _WIN32
double after[3]{};
Require(getloadavg(after, 3) == 3);
const auto scaled = [](double average) { return static_cast<std::uint32_t>(average * 2048.0 + 0.5); };
for (int index = 0; index < 3; ++index) Require(load.ldavg[index] == scaled(before[index]) || load.ldavg[index] == scaled(after[index]));
#endif
LoadAverage named{};
length = sizeof(named);
Require(sysctlbyname_nid_postfix("vm.loadavg", &named, &length, nullptr, 0) == 0 && length == sizeof(named) && named.fscale == 2048);
Require(*__error_nid_postfix() == 13);
int namedMib[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t mibLength = 3;
Require(sysctlnametomib_nid_postfix("vm.loadavg", namedMib, &mibLength) == 0 && mibLength == 2);
Require(namedMib[0] == 2 && namedMib[1] == 2 && namedMib[2] == 0x5a5a5a5a);
length = sizeof(load);
Require(sysctl_nid_postfix(mib, 2, &load, &length, &load, sizeof(load)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckLeafWithTrailingComponent() {
const int leaves[][2] = {{6, 3}, {6, 2}, {6, 5}, {6, 7}, {1, 21}, {1, 24}, {1, 37}, {1, 50}, {2, 2}};
for (const auto& leaf : leaves) {
const int mib[] = {leaf[0], leaf[1], 0};
char buffer[8] = {};
std::size_t length = sizeof(buffer);
*__error_nid_postfix() = 13;
Require(sysctl_nid_postfix(mib, 3, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 20);
Require(sysctl_nid_postfix(mib, 3, buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 20);
Require(length == sizeof(buffer));
}
}
static void CheckMeasuredAbsentSysctlMibs() {
static constexpr struct {
int mib[3];
std::uint32_t length;
} cases[] = {
{{1, 2147482816, 2147482814}, 3},
{{1, 2147483151}, 2},
{{1, 2147483182, 2147483181}, 3},
{{1, 2147482838, 2147482834}, 3},
};
for (const auto& entry : cases) {
unsigned char buffer[64];
std::memset(buffer, 0xaa, sizeof(buffer));
std::size_t length = sizeof(buffer);
*__error_nid_postfix() = 77;
Require(sysctl_nid_postfix(entry.mib, entry.length, buffer, &length, nullptr, 0) == -1);
Require(*__error_nid_postfix() == 2 && length == sizeof(buffer));
for (const auto byte : buffer) Require(byte == 0xaa);
length = 77;
*__error_nid_postfix() = 77;
Require(sysctl_nid_postfix(entry.mib, entry.length, nullptr, &length, nullptr, 0) == -1);
Require(*__error_nid_postfix() == 2 && length == 77);
std::memset(buffer, 0xaa, sizeof(buffer));
*__error_nid_postfix() = 77;
Require(sysctl_nid_postfix(entry.mib, entry.length, buffer, nullptr, nullptr, 0) == -1);
Require(*__error_nid_postfix() == 2);
for (const auto byte : buffer) Require(byte == 0xaa);
*__error_nid_postfix() = 77;
Require(sysctl_nid_postfix(entry.mib, entry.length, nullptr, nullptr, nullptr, 0) == -1);
Require(*__error_nid_postfix() == 2);
bool threw = false;
try {
sysctl_nid_postfix(entry.mib, entry.length, buffer, &length, buffer, sizeof(buffer));
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
}
}
static void CheckVersionLimits() {
unsigned char first[4];
unsigned char second[4];
std::memset(first, 0xaa, sizeof(first));
std::memset(second, 0xaa, sizeof(second));
*__error_nid_postfix() = 13;
Require(sceKernelGetSystemExVersion(reinterpret_cast<char*>(first + 1), reinterpret_cast<char*>(second + 1)) == 0 && *__error_nid_postfix() == 13);
Require(first[0] == 0xaa && first[1] == 0 && first[2] == 0xaa && second[0] == 0xaa && second[1] == 0 && second[2] == 0xaa);
std::memset(first, 0xaa, sizeof(first));
Require(sceKernelGetSystemExVersion(reinterpret_cast<char*>(first), nullptr) == 22 && first[0] == 0xaa);
Require(sceKernelGetSystemExVersion(nullptr, reinterpret_cast<char*>(first)) == 22 && first[0] == 0xaa);
Require(sceKernelGetSystemExVersion(nullptr, nullptr) == 22 && *__error_nid_postfix() == 13);
std::memset(first, 0xaa, sizeof(first));
Require(sysKernelGetLowerLimitSysexVersion_nid_postfix(reinterpret_cast<char*>(first + 1)) == 0);
Require(first[0] == 0xaa && first[1] == 0 && first[2] == 0xaa);
Require(sysKernelGetLowerLimitSysexVersion_nid_postfix(nullptr) == SCE_KERNEL_ERROR_EINVAL);
struct {
std::uint32_t version;
std::uint32_t after;
} update{0xaaaaaaaau, 0xaaaaaaaau};
Require(sysKernelGetLowerLimitUpdVersion_nid_postfix(&update.version) == 0 && update.version == 0 && update.after == 0xaaaaaaaau);
Require(sysKernelGetLowerLimitUpdVersion_nid_postfix(nullptr) == SCE_KERNEL_ERROR_EINVAL && *__error_nid_postfix() == 13);
update = {0xaaaaaaaau, 0xaaaaaaaau};
Require(sysKernelGetUpdVersion_nid_postfix(&update.version) == 0 && update.version == 0 && update.after == 0xaaaaaaaau);
Require(sysKernelGetUpdVersion_nid_postfix(nullptr) == SCE_KERNEL_ERROR_EINVAL && *__error_nid_postfix() == 13);
Require(sysKernelGetManufacturingMode_nid_postfix() == 0 && *__error_nid_postfix() == 13);
Require(sysKernelGetIntdevModeForInternalLibc_nid_postfix() == 0 && *__error_nid_postfix() == 13);
Require(sysKernelGetIntdevModeForRcmgr_nid_postfix() == 0 && *__error_nid_postfix() == 13);
}
static void CheckSystemSwVersion() {
*__error_nid_postfix() = 13;
Require(sceKernelGetSystemSwVersion_nid_postfix(nullptr) == 0 && *__error_nid_postfix() == 13);
const std::uint64_t sizes[] = {0, 1, 24, 39, 40, 41, 48, 64, 0x1000, ~0ull};
for (const std::uint64_t size : sizes) {
struct {
std::uint64_t prefix;
SceKernelSystemSwVersion version;
unsigned char suffix[88];
} storage;
std::memset(&storage, 0xaa, sizeof(storage));
storage.version.size = size;
*__error_nid_postfix() = 13;
Require(sceKernelGetSystemSwVersion_nid_postfix(&storage.version) == 0 && *__error_nid_postfix() == 13);
Require(storage.prefix == 0xaaaaaaaaaaaaaaaaull && storage.version.size == size);
Require(std::strcmp(storage.version.versionString, "01.000.000") == 0);
for (std::size_t i = sizeof("01.000.000"); i < sizeof(storage.version.versionString); ++i) {
Require(storage.version.versionString[i] == 0);
}
Require(storage.version.version == 0x01000000);
for (unsigned char byte : storage.suffix) Require(byte == 0xaa);
}
}
static void CheckPseudoRandomSysctl() {
unsigned char first[128];
unsigned char second[128];
const auto untouchedFrom = [&first](std::size_t from) {
for (std::size_t i = from; i < sizeof(first); ++i)
if (first[i] != 0xaa) return false;
return true;
};
*__error_nid_postfix() = 13;
std::memset(first, 0xaa, sizeof(first));
std::memset(second, 0xaa, sizeof(second));
std::size_t length = 64;
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", first, &length, nullptr, 0) == 0 && length == 64 && untouchedFrom(64) && !untouchedFrom(0));
length = 64;
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", second, &length, nullptr, 0) == 0 && length == 64);
Require(std::memcmp(first, second, 64) != 0);
Require(*__error_nid_postfix() == 13);
static constexpr std::size_t larger[] = {65, 128};
for (std::size_t asked : larger) {
std::memset(first, 0xaa, sizeof(first));
length = asked;
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", first, &length, nullptr, 0) == 0 && length == 64 && untouchedFrom(64) && !untouchedFrom(0));
}
Require(*__error_nid_postfix() == 13);
static constexpr std::size_t smaller[] = {0, 1, 63};
for (std::size_t asked : smaller) {
std::memset(first, 0xaa, sizeof(first));
length = asked;
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", first, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == asked && untouchedFrom(asked));
if (asked == 63) Require(!untouchedFrom(0));
}
static constexpr std::size_t presets[] = {0, 1, 64, 100, 4096};
for (std::size_t preset : presets) {
length = preset;
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", nullptr, &length, nullptr, 0) == 0 && length == 64 && *__error_nid_postfix() == 13);
}
std::memset(first, 0xaa, sizeof(first));
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", first, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 12 && untouchedFrom(0));
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", nullptr, nullptr, nullptr, 0) == 0 && *__error_nid_postfix() == 13);
length = 64;
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", first, &length, first, 64) == -1 && *__error_nid_postfix() == 1);
}
static void CheckOvercommitSysctl() {
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctlbyname_nid_postfix("vm.overcommit", nullptr, &length, nullptr, 0) == 0 && length == sizeof(int));
int value = -1;
length = sizeof(value);
Require(sysctlbyname_nid_postfix("vm.overcommit", &value, &length, nullptr, 0) == 0 && value == 0 && length == sizeof(int));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[4] = {0xaa, 0xaa, 0xaa, 0xaa};
length = 2;
Require(sysctlbyname_nid_postfix("vm.overcommit", bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 2 && bytes[2] == 0xaa && bytes[3] == 0xaa);
bool threw = false;
length = sizeof(value);
try {
sysctlbyname_nid_postfix("vm.overcommit", &value, &length, &value, sizeof(value));
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
}
static void CheckSdkVersionSysctl() {
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctlbyname_nid_postfix("kern.sdk_version", nullptr, &length, nullptr, 0) == 0 && length == sizeof(std::uint32_t));
std::uint32_t version = 0;
length = sizeof(version);
Require(sysctlbyname_nid_postfix("kern.sdk_version", &version, &length, nullptr, 0) == 0 && version == 0x01000000 && length == sizeof(std::uint32_t));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[4] = {0xaa, 0xaa, 0xaa, 0xaa};
length = 2;
Require(sysctlbyname_nid_postfix("kern.sdk_version", bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 2 && bytes[2] == 0xaa && bytes[3] == 0xaa);
length = sizeof(version);
Require(sysctlbyname_nid_postfix("kern.sdk_version", &version, &length, &version, sizeof(version)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckArandomSysctl() {
const int mib[] = {1, 37};
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == 0);
length = 64;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == 64);
length = 300;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == 256);
Require(sysctl_nid_postfix(mib, 2, nullptr, nullptr, nullptr, 0) == 0);
Require(*__error_nid_postfix() == 13);
unsigned char first[64] = {};
unsigned char second[64] = {};
length = sizeof(first);
Require(sysctl_nid_postfix(mib, 2, first, &length, nullptr, 0) == 0 && length == sizeof(first));
length = sizeof(second);
Require(sysctl_nid_postfix(mib, 2, second, &length, nullptr, 0) == 0 && length == sizeof(second));
Require(std::memcmp(first, second, sizeof(first)) != 0);
Require(*__error_nid_postfix() == 13);
unsigned char named[64] = {};
length = sizeof(named);
Require(sysctlbyname_nid_postfix("kern.arandom", named, &length, nullptr, 0) == 0 && length == sizeof(named));
Require(*__error_nid_postfix() == 13);
length = sizeof(first);
Require(sysctl_nid_postfix(mib, 2, first, &length, first, sizeof(first)) == -1 && *__error_nid_postfix() == 1);
*__error_nid_postfix() = 13;
unsigned char big[300] = {};
length = sizeof(big);
Require(sysctl_nid_postfix(mib, 2, big, &length, nullptr, 0) == 0 && length == 256);
unsigned char small[16] = {};
length = sizeof(small);
Require(sysctl_nid_postfix(mib, 2, small, &length, nullptr, 0) == 0 && length == sizeof(small));
Require(sysctl_nid_postfix(mib, 2, first, nullptr, nullptr, 0) == 0);
Require(*__error_nid_postfix() == 13);
}
struct VmRange {
std::uint64_t start;
std::uint64_t end;
std::int32_t protection;
};
static std::vector<VmRange> ReadVmmap(const int* mib) {
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 4, nullptr, &length, nullptr, 0) == 0 && length != 0 && length % 8 == 0);
std::vector<unsigned char> buffer(length * 4 / 3);
length = buffer.size();
Require(sysctl_nid_postfix(mib, 4, buffer.data(), &length, nullptr, 0) == 0 && length != 0 && length <= buffer.size());
std::vector<VmRange> ranges;
for (std::size_t at = 0; at < length;) {
std::int32_t size = 0;
std::memcpy(&size, buffer.data() + at, sizeof(size));
Require(size > 136 && size % 8 == 0 && at + static_cast<std::size_t>(size) <= length);
Require(std::memchr(buffer.data() + at + 136, 0, static_cast<std::size_t>(size) - 136) != nullptr);
VmRange range{};
std::memcpy(&range.start, buffer.data() + at + 8, sizeof(range.start));
std::memcpy(&range.end, buffer.data() + at + 16, sizeof(range.end));
std::memcpy(&range.protection, buffer.data() + at + 56, sizeof(range.protection));
Require(range.start < range.end && (ranges.empty() || ranges.back().end <= range.start));
ranges.push_back(range);
at += static_cast<std::size_t>(size);
}
return ranges;
}
static void CheckVmmapSysctl() {
const int self = getpid_nid_postfix();
const int mib[] = {1, 14, 32, self};
constexpr std::size_t Bytes = 0x10000;
*__error_nid_postfix() = 13;
void* mapped = mmap_nid_postfix(nullptr, Bytes, 3, 0x1002, -1, 0);
Require(mapped != reinterpret_cast<void*>(static_cast<std::uintptr_t>(-1)));
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(mapped));
auto ranges = ReadVmmap(mib);
const auto covering = std::find_if(ranges.begin(), ranges.end(), [&](const VmRange& range) { return range.start <= address && address + Bytes <= range.end; });
Require(covering != ranges.end() && (covering->protection & 3) == 3);
Require(munmap_nid_postfix(mapped, Bytes) == 0);
ranges = ReadVmmap(mib);
Require(std::none_of(ranges.begin(), ranges.end(), [&](const VmRange& range) { return range.start < address + Bytes && address < range.end; }));
Require(*__error_nid_postfix() == 13);
unsigned char truncated[32];
std::memset(truncated, 0xaa, sizeof(truncated));
std::size_t length = 16;
Require(sysctl_nid_postfix(mib, 4, truncated, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 16 && truncated[16] == 0xaa);
length = sizeof(truncated);
Require(sysctl_nid_postfix(mib, 4, truncated, &length, truncated, sizeof(truncated)) == -1 && *__error_nid_postfix() == 1);
const int foreign[] = {1, 14, 32, self + 1000};
Require(sysctl_nid_postfix(foreign, 4, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
const int current[] = {1, 14, 32, -1};
Require(sysctl_nid_postfix(current, 4, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
Require(sysctl_nid_postfix(mib, 3, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
const int tooLong[] = {1, 14, 32, self, 0};
Require(sysctl_nid_postfix(tooLong, 5, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
}
static void CheckEnvSysctl() {
const int self = getpid_nid_postfix();
const int mib[] = {1, 14, 35, self};
*__error_nid_postfix() = 13;
std::size_t length = 7;
Require(sysctl_nid_postfix(mib, 4, nullptr, &length, nullptr, 0) == 0 && length == 0);
unsigned char buffer[16];
std::memset(buffer, 0xaa, sizeof(buffer));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mib, 4, buffer, &length, nullptr, 0) == 0 && length == 0 && buffer[0] == 0xaa);
Require(*__error_nid_postfix() == 13);
length = sizeof(buffer);
Require(sysctl_nid_postfix(mib, 4, buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 1);
const int foreign[] = {1, 14, 35, self + 1000};
Require(sysctl_nid_postfix(foreign, 4, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
const int current[] = {1, 14, 35, -1};
Require(sysctl_nid_postfix(current, 4, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
Require(sysctl_nid_postfix(mib, 3, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
const int tooLong[] = {1, 14, 35, self, 0};
Require(sysctl_nid_postfix(tooLong, 5, nullptr, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
}
static void CheckPseudoRandomMibSysctl() {
const int mib[] = {1, 50};
*__error_nid_postfix() = 13;
std::size_t length = 7;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == 64);
Require(*__error_nid_postfix() == 13);
Require(sysctl_nid_postfix(mib, 2, nullptr, nullptr, nullptr, 0) == 0);
unsigned char bytes[80];
std::memset(bytes, 0xaa, sizeof(bytes));
length = 64;
Require(sysctl_nid_postfix(mib, 2, bytes, &length, nullptr, 0) == 0 && length == 64);
bool changed = false;
for (std::size_t i = 0; i < 64; ++i) changed = changed || bytes[i] != 0xaa;
Require(changed && bytes[64] == 0xaa && bytes[79] == 0xaa);
unsigned char other[64] = {};
length = sizeof(other);
Require(sysctl_nid_postfix(mib, 2, other, &length, nullptr, 0) == 0 && length == sizeof(other));
Require(std::memcmp(bytes, other, sizeof(other)) != 0);
unsigned char shortBuffer[64];
std::memset(shortBuffer, 0xaa, sizeof(shortBuffer));
length = 63;
Require(sysctl_nid_postfix(mib, 2, shortBuffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
bool shortChanged = false;
for (std::size_t i = 0; i < 63; ++i) shortChanged = shortChanged || shortBuffer[i] != 0xaa;
Require(length == 63 && shortChanged && shortBuffer[63] == 0xaa);
std::memset(shortBuffer, 0xaa, sizeof(shortBuffer));
Require(sysctl_nid_postfix(mib, 2, shortBuffer, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
for (unsigned char byte : shortBuffer) Require(byte == 0xaa);
int value = 0;
length = sizeof(value);
bool threw = false;
try {
sysctl_nid_postfix(mib, 2, &value, &length, &value, sizeof(value));
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
}
static void CheckNameToMib() {
struct Expected {
const char* name;
int mib[3];
std::size_t length;
};
const Expected expected[] = {
{"hw.model", {6, 2}, 2},
{"hw.ncpu", {6, 3}, 2},
{"hw.pagesize", {6, 7}, 2},
{"hw.physmem", {6, 5}, 2},
{"hw.realmem", {6, 12}, 2},
{"kern.arandom", {1, 37}, 2},
{"kern.boottime", {1, 21}, 2},
{"kern.rng_pseudo", {1, 50}, 2},
{"kern.proc.pathname", {1, 14, 12}, 3},
};
*__error_nid_postfix() = 13;
for (const auto& entry : expected) {
std::size_t size = 0;
Require(sysctlnametomib_nid_postfix(entry.name, nullptr, &size) == 0 && size == entry.length);
int mib[5] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
size = 5;
Require(sysctlnametomib_nid_postfix(entry.name, mib, &size) == 0 && size == entry.length);
Require(std::memcmp(mib, entry.mib, entry.length * sizeof(int)) == 0 && mib[entry.length] == 0x5a5a5a5a);
}
Require(*__error_nid_postfix() == 13);
int mib[4] = {};
std::size_t size = 4;
Require(sysctlnametomib_nid_postfix("hw.ncpu", mib, &size) == 0 && size == 2);
int processors = 0;
std::size_t length = sizeof(processors);
Require(sysctl_nid_postfix(mib, static_cast<std::uint32_t>(size), &processors, &length, nullptr, 0) == 0);
Require(processors == static_cast<int>(sysconf_nid_postfix(58)));
size = 4;
Require(sysctlnametomib_nid_postfix("hw.realmem", mib, &size) == 0 && size == 2);
std::uint64_t realmem = 0;
length = sizeof(realmem);
Require(sysctl_nid_postfix(mib, static_cast<std::uint32_t>(size), &realmem, &length, nullptr, 0) == 0);
std::uint64_t namedRealmem = 0;
length = sizeof(namedRealmem);
Require(sysctlbyname_nid_postfix("hw.realmem", &namedRealmem, &length, nullptr, 0) == 0 && realmem == namedRealmem);
size = 4;
Require(sysctlnametomib_nid_postfix("kern.proc.pathname", mib, &size) == 0 && size == 3);
mib[3] = -1;
char path[32] = {};
length = sizeof(path);
Require(sysctl_nid_postfix(mib, 4, path, &length, nullptr, 0) == 0 && std::strcmp(path, "/app0/eboot.bin") == 0);
int truncated[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
size = 1;
Require(sysctlnametomib_nid_postfix("hw.ncpu", truncated, &size) == -1 && *__error_nid_postfix() == 12);
Require(size == 1 && truncated[0] == 6 && truncated[1] == 0x5a5a5a5a);
size = 0;
Require(sysctlnametomib_nid_postfix("hw.ncpu", truncated, &size) == -1 && *__error_nid_postfix() == 12);
Require(size == 0 && truncated[0] == 6);
int rngMib[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
size = 3;
Require(sysctlnametomib_nid_postfix("kern.rng_pseudo", rngMib, &size) == 0 && size == 2);
Require(rngMib[0] == 1 && rngMib[1] == 50 && rngMib[2] == 0x5a5a5a5a);
size = 2;
Require(sysctl_nid_postfix(rngMib, static_cast<std::uint32_t>(size), nullptr, &length, nullptr, 0) == 0 && length == 64);
rngMib[0] = rngMib[1] = rngMib[2] = 0x5a5a5a5a;
size = 1;
Require(sysctlnametomib_nid_postfix("kern.rng_pseudo", rngMib, &size) == -1 && *__error_nid_postfix() == 12);
Require(size == 1 && rngMib[0] == 1 && rngMib[1] == 0x5a5a5a5a);
size = 4;
Require(sysctlnametomib_nid_postfix("", mib, &size) == -1 && *__error_nid_postfix() == 2);
Require(sysctlnametomib_nid_postfix("machdep.cacheline_size", mib, &size) == -1 && *__error_nid_postfix() == 2);
char tooLong[1025];
std::memset(tooLong, 'a', sizeof(tooLong) - 1);
tooLong[sizeof(tooLong) - 1] = 0;
int tooLongMib[4] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t tooLongMibSize = 4;
Require(sysctlnametomib_nid_postfix(tooLong, tooLongMib, &tooLongMibSize) == -1 && *__error_nid_postfix() == 63);
Require(tooLongMibSize == 4 && tooLongMib[0] == 0x5a5a5a5a && tooLongMib[1] == 0x5a5a5a5a && tooLongMib[2] == 0x5a5a5a5a && tooLongMib[3] == 0x5a5a5a5a);
tooLong[1023] = 0;
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix(tooLong, tooLongMib, &tooLongMibSize) == -1 && *__error_nid_postfix() == 2 && tooLongMibSize == 4);
Require(tooLongMib[0] == 0x5a5a5a5a && tooLongMib[1] == 0x5a5a5a5a && tooLongMib[2] == 0x5a5a5a5a && tooLongMib[3] == 0x5a5a5a5a);
bool threw = false;
try {
sysctlnametomib_nid_postfix(nullptr, mib, &size);
} catch (const std::invalid_argument&) {
threw = true;
}
Require(threw);
threw = false;
try {
sysctlnametomib_nid_postfix("hw.ncpu", mib, nullptr);
} catch (const std::invalid_argument&) {
threw = true;
}
Require(threw);
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix("kern.anyps5_no_such_name", mib, &size) == -1 && *__error_nid_postfix() == 2);
}
static void CheckUnknownRootsAndTopLevelNames() {
for (const int root : {99, 10, 255, -1, -5}) {
const int mib[] = {root, 1};
int value = 0x5a5a5a5a;
std::size_t length = sizeof(value);
*__error_nid_postfix() = 13;
Require(sysctl_nid_postfix(mib, 2, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
Require(value == 0x5a5a5a5a && length == sizeof(value));
}
struct TopLevel {
const char* name;
int number;
};
for (const TopLevel& node : {TopLevel{"sysctl", 0}, TopLevel{"kern", 1}, TopLevel{"vm", 2}, TopLevel{"vfs", 3}, TopLevel{"net", 4},
TopLevel{"debug", 5}, TopLevel{"hw", 6}, TopLevel{"machdep", 7}, TopLevel{"user", 8}, TopLevel{"p1003_1b", 9}}) {
for (const bool dotted : {false, true}) {
const std::string name = std::string(node.name) + (dotted ? "." : "");
int mib[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t size = 3;
Require(sysctlnametomib_nid_postfix(name.c_str(), mib, &size) == 0 && size == 1 && mib[0] == node.number && mib[1] == 0x5a5a5a5a);
int value = 0x5a5a5a5a;
std::size_t length = sizeof(value);
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(name.c_str(), &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(value == 0x5a5a5a5a && length == sizeof(value));
}
}
int mib[3] = {0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
std::size_t size = 3;
Require(sysctlnametomib_nid_postfix("hw.ncpu.", mib, &size) == 0 && size == 2 && mib[0] == 6 && mib[1] == 3);
for (const char* name : {"kern..", ".", "kern.anyps5.x", "kernel"}) {
size = 3;
*__error_nid_postfix() = 13;
Require(sysctlnametomib_nid_postfix(name, mib, &size) == -1 && *__error_nid_postfix() == 2);
}
int value = 0;
std::size_t length = sizeof(value);
Require(sysctlbyname_nid_postfix("hw.ncpu.", &value, &length, nullptr, 0) == 0 && value > 0 && length == sizeof(value));
std::string tooLong(1024, 'a');
length = sizeof(value);
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(tooLong.c_str(), &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 63);
tooLong.resize(1023);
*__error_nid_postfix() = 13;
Require(sysctlbyname_nid_postfix(tooLong.c_str(), &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
}
static void CheckSysctlPointerFaults() {
constexpr std::size_t page = 0x4000;
void* memory = nullptr;
Require(sceKernelMapFlexibleMemory(&memory, page, 3, 0) == 0 && memory != nullptr);
auto* readOnlyLength = static_cast<std::size_t*>(memory);
*readOnlyLength = sizeof(int);
Require(sceKernelMprotect(memory, page, 1) == 0);
const auto fails = [](int result) { return result == -1 && *__error_nid_postfix() == 14; };
auto* guard = static_cast<char*>(nullptr);
void* pages = nullptr;
Require(sceKernelMapFlexibleMemory(&pages, page * 2, 3, 0) == 0 && pages != nullptr);
guard = static_cast<char*>(pages) + page;
Require(sceKernelMprotect(guard, page, 0) == 0);
char* crossing = guard - 4;
std::memcpy(crossing, "kern", 4);
std::size_t nameLength = sizeof(int);
int nameValue = 0;
Require(fails(sysctlbyname_nid_postfix(reinterpret_cast<const char*>(0x10), &nameValue, &nameLength, nullptr, 0)));
Require(fails(sysctlbyname_nid_postfix(nullptr, &nameValue, &nameLength, nullptr, 0)));
Require(fails(sysctlbyname_nid_postfix(crossing, &nameValue, &nameLength, nullptr, 0)));
Require(sysctlbyname_nid_postfix("hw.ncpu", &nameValue, &nameLength, nullptr, 0) == 0 && nameValue > 0);
Require(fails(sysctlbyname_nid_postfix("hw.ncpu", &nameValue, reinterpret_cast<std::size_t*>(0x10), nullptr, 0)));
Require(fails(sysctlbyname_nid_postfix("hw.ncpu", reinterpret_cast<void*>(0x10), &nameLength, nullptr, 0)));
const int mib[] = {6, 3};
const int absent[] = {1, 6};
const auto unreadable = reinterpret_cast<const int*>(0x10);
const auto badLength = reinterpret_cast<std::size_t*>(0x10);
int value = 0;
std::size_t length = sizeof(value);
Require(fails(sysctl_nid_postfix(unreadable, 2, &value, &length, nullptr, 0)));
Require(fails(sysctl_nid_postfix(nullptr, 2, &value, &length, nullptr, 0)));
Require(fails(sysctl_nid_postfix(mib, 2, &value, badLength, nullptr, 0)));
Require(fails(sysctl_nid_postfix(absent, 2, &value, badLength, nullptr, 0)));
Require(fails(sysctl_nid_postfix(mib, 2, reinterpret_cast<void*>(0x10), &length, nullptr, 0)) && length == sizeof(value));
Require(fails(sysctl_nid_postfix(mib, 2, nullptr, badLength, nullptr, 0)));
Require(fails(sysctl_nid_postfix(mib, 2, &value, readOnlyLength, nullptr, 0)) && value != 0);
Require(fails(sysctl_nid_postfix(mib, 2, nullptr, readOnlyLength, nullptr, 0)));
length = 0;
Require(sysctl_nid_postfix(mib, 2, reinterpret_cast<void*>(0x10), &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12 && length == 0);
Require(sysctl_nid_postfix(unreadable, 1, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(sysctl_nid_postfix(unreadable, 25, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(sysctl_nid_postfix(absent, 2, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 2);
const int arandom[] = {1, 37};
std::uint8_t bytes[8] = {};
length = sizeof(bytes);
Require(fails(sysctl_nid_postfix(arandom, 2, reinterpret_cast<void*>(0x10), &length, nullptr, 0)) && length == sizeof(bytes));
Require(fails(sysctl_nid_postfix(arandom, 2, bytes, badLength, nullptr, 0)));
Require(sysctl_nid_postfix(arandom, 2, bytes, &length, nullptr, 0) == 0 && length == sizeof(bytes));
}
static void CheckSysconfMeasuredNames() {
struct Entry {
int name;
std::int64_t value;
};
static constexpr Entry constants[] = {
{6, 1}, {7, -1}, {8, 200112}, {9, 99}, {10, 2048}, {11, 99}, {12, 1000}, {13, 0}, {14, 32},
{15, 2048}, {16, 255}, {17, 199212}, {18, 200112}, {19, -1}, {20, 1}, {21, -1}, {22, 200112},
{23, -1}, {24, -1}, {25, 200112}, {28, 200112}, {29, 200112}, {30, -1}, {31, 200112}, {32, 200112},
{33, 200112}, {34, -1}, {35, 200112}, {36, 200112}, {37, 200112}, {38, 200112}, {39, 200112},
{40, -1}, {41, 200112}, {42, 16}, {43, 1024}, {44, 0}, {45, 2147483647}, {46, -1}, {48, 62},
{49, 30}, {50, 2147483647}, {51, 128}, {52, 32}, {59, -1}, {60, -1}, {61, -1}, {62, -1}, {63, -1},
{64, -1}, {65, 200112}, {66, 200112}, {67, -1}, {68, 200112}, {74, 200112}, {75, 64}, {76, 200112},
{77, 1}, {78, 1}, {79, 200112}, {80, 200112}, {81, -1}, {82, 200112}, {83, 200112}, {84, 200112},
{85, 4}, {86, 256}, {87, 200112}, {88, 200112}, {89, 200112}, {90, -1}, {91, -1}, {93, 16384},
{94, -1}, {95, 200112}, {96, 200112}, {97, -1}, {101, 255}, {102, -1}, {103, -1}, {104, -1},
{105, 1}, {106, -1}, {107, 64}, {108, -1}, {109, -1}, {110, -1}, {111, -1}, {112, -1}, {113, -1},
{114, -1}, {115, -1}, {118, 200112}, {119, 200112}, {120, 32}, {122, 8},
{1, 262144}, {3, 128}, {4, 1023}, {47, 16384}, {56, 1024}, {72, 255}, {73, 33},
};
for (const Entry& entry : constants) {
*__error_nid_postfix() = 77;
Require(sysconf_nid_postfix(entry.name) == entry.value);
Require(*__error_nid_postfix() == 77);
}
*__error_nid_postfix() = 77;
Require(sysconf_nid_postfix(27) == -1);
Require(*__error_nid_postfix() == 2);
static constexpr int rejected[] = {-1, 0, 53, 54, 55, 69, 70, 71, 92, 98, 99, 100, 116, 117, 123, 124, 125, 126, 127, 128, 129, 130, 150, 200, 201, 1000};
for (int name : rejected) {
*__error_nid_postfix() = 77;
Require(sysconf_nid_postfix(name) == -1);
Require(*__error_nid_postfix() == 22);
}
}
int main() {
CheckUnknownRootsAndTopLevelNames();
CheckProcessorCountSysctl();
CheckSysctlPointerFaults();
CheckPageSizeSysctl();
CheckPhysicalMemorySysctl(5, "hw.physmem");
CheckPhysicalMemorySysctl(12, "hw.realmem");
CheckModelSysctl();
CheckMeasuredIntegerSysctl();
CheckTscFrequencySysctl();
CheckUnansweredSysctl();
CheckUnknownSysctlName();
CheckPathnameSysctl();
CheckProcessSysctl();
CheckSystemStringSysctl();
CheckSystemStringNames();
CheckOsReleaseDateSysctl();
CheckBootTimeSysctl();
CheckLoadAverageSysctl();
CheckLeafWithTrailingComponent();
CheckMeasuredAbsentSysctlMibs();
CheckSystemSwVersion();
CheckVersionLimits();
CheckPseudoRandomSysctl();
CheckSdkVersionSysctl();
CheckOvercommitSysctl();
CheckArandomSysctl();
CheckVmmapSysctl();
CheckEnvSysctl();
CheckPseudoRandomMibSysctl();
CheckNameToMib();
CheckSysconfMeasuredNames();
*__error_nid_postfix() = 13;
Require(sysconf_nid_postfix(1) == 262144);
Require(sysconf_nid_postfix(3) == 128);
GuestResourceLimit nofileLimit{};
Require(getrlimit_nid_postfix(8, &nofileLimit) == 0);
Require(sysconf_nid_postfix(5) == nofileLimit.rlim_cur);
GuestResourceLimit nprocLimit{};
Require(getrlimit_nid_postfix(7, &nprocLimit) == 0);
Require(nprocLimit.rlim_cur == 1604);
Require(sysconf_nid_postfix(2) == nprocLimit.rlim_cur);
GuestResourceLimit stackLimit{};
Require(getrlimit_nid_postfix(3, &stackLimit) == 0);
Require(sysconf_nid_postfix(2) != stackLimit.rlim_cur);
Require(sysconf_nid_postfix(4) == 1023);
Require(sysconf_nid_postfix(26) == std::min<std::int64_t>(nofileLimit.rlim_cur, 32767));
Require(sysconf_nid_postfix(72) == 255);
Require(sysconf_nid_postfix(73) == 33);
Require(sysconf_nid_postfix(47) == 0x4000);
Require(sysconf_nid_postfix(56) == 1024);
Require(getpagesize_nid_postfix() == sysconf_nid_postfix(47));
Require(sysconf_nid_postfix(57) > 0);
Require(sysconf_nid_postfix(58) > 0);
Require(sysconf_nid_postfix(121) > 0);
Require(*__error_nid_postfix() == 13);
Require(sysconf_nid_postfix(-1) == -1); // verifies full-width signed return
Require(*__error_nid_postfix() == 22);
Require(sysconf_nid_postfix(0x7fffffff) == -1);
Require(environ_nid_postfix && !environ_nid_postfix[0]);
}