mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-05 13:20:11 +00:00
fix(libSceJson2): export mutable default pointers
This commit is contained in:
1 parent
3d13db3ef9
commit
24fd96dcc8
3 files changed
+105
-6
No files matched your search
@@ -1456,10 +1456,16 @@ void ResetDefaults(bool releaseMissing = false) {
|
||||
auto& defaults = SharedDefaults();
|
||||
for (unsigned type = 0; type < 8; ++type) {
|
||||
if (defaults.ready[type]) {
|
||||
if (releaseMissing && type == TypeString) defaults.values[type].string = _ZN3sce4Json5Value12s_nullstringE;
|
||||
if (releaseMissing && type == TypeArray) defaults.values[type].array = _ZN3sce4Json5Value11s_nullarrayE;
|
||||
if (releaseMissing && type == TypeObject) defaults.values[type].object = _ZN3sce4Json5Value12s_nullobjectE;
|
||||
const bool missing = type >= TypeString && !defaults.values[type].payload;
|
||||
Destroy(defaults.values[type]);
|
||||
if (releaseMissing && missing) Release(nullptr);
|
||||
} else if (releaseMissing && type >= TypeString) Release(nullptr);
|
||||
if (releaseMissing && type == TypeString) _ZN3sce4Json5Value12s_nullstringE = nullptr;
|
||||
if (releaseMissing && type == TypeArray) _ZN3sce4Json5Value11s_nullarrayE = nullptr;
|
||||
if (releaseMissing && type == TypeObject) _ZN3sce4Json5Value12s_nullobjectE = nullptr;
|
||||
defaults.values[type] = {};
|
||||
defaults.ready[type] = false;
|
||||
}
|
||||
@@ -1538,6 +1544,9 @@ void CreateDefault(ValueType type) {
|
||||
if constexpr (std::is_same_v<T, String>) Construct(*handle, std::string_view{});
|
||||
else Construct(*handle);
|
||||
}
|
||||
if constexpr (std::is_same_v<T, String>) _ZN3sce4Json5Value12s_nullstringE = handle;
|
||||
else if constexpr (std::is_same_v<T, Array>) _ZN3sce4Json5Value11s_nullarrayE = handle;
|
||||
else _ZN3sce4Json5Value12s_nullobjectE = handle;
|
||||
}
|
||||
|
||||
int InitializeResources(void* self, const void* parameter, std::int32_t format, bool modern) {
|
||||
@@ -1559,9 +1568,8 @@ int InitializeResources(void* self, const void* parameter, std::int32_t format,
|
||||
state.fallback = static_cast<Value*>(Allocate(sizeof(Value)));
|
||||
if (state.fallback) Construct(*state.fallback);
|
||||
state.internalMutex = CreateKernelMutex();
|
||||
const auto& defaults = SharedDefaults();
|
||||
const bool admitted = defaults.values[TypeString].string && defaults.values[TypeArray].array &&
|
||||
defaults.values[TypeObject].object && state.fallback && state.internalMutex;
|
||||
const bool admitted = _ZN3sce4Json5Value12s_nullstringE && _ZN3sce4Json5Value11s_nullarrayE &&
|
||||
_ZN3sce4Json5Value12s_nullobjectE && state.fallback && state.internalMutex;
|
||||
if (admitted) state.recoveryMutex = ModernValues() ? CreateKernelMutex() : state.internalMutex;
|
||||
if (!admitted || !state.recoveryMutex) { ReleaseInitialization(); return JsonErrorOutOfMemory; }
|
||||
state.paddedStringGrowth = CompiledSdk() > 0x044fffff;
|
||||
@@ -1573,6 +1581,7 @@ int InitializeResources(void* self, const void* parameter, std::int32_t format,
|
||||
const Node& Typed(const Value* self, ValueType requested, bool* usedDefault = nullptr) {
|
||||
const auto fallback = [&]() -> const Node& {
|
||||
if (usedDefault) *usedDefault = true;
|
||||
if (usedDefault && requested >= TypeString) return SharedDefaults().values[requested];
|
||||
return Defaults(requested);
|
||||
};
|
||||
if (self->type == requested ||
|
||||
@@ -2658,6 +2667,9 @@ extern const bool _ZN3sce4Json5Value10s_nullboolE = false;
|
||||
extern const std::int64_t _ZN3sce4Json5Value13s_nullintegerE = 0;
|
||||
extern const std::uint64_t _ZN3sce4Json5Value14s_nulluintegerE = 0;
|
||||
extern const double _ZN3sce4Json5Value10s_nullrealE = 0;
|
||||
String* _ZN3sce4Json5Value12s_nullstringE = nullptr;
|
||||
Array* _ZN3sce4Json5Value11s_nullarrayE = nullptr;
|
||||
Object* _ZN3sce4Json5Value12s_nullobjectE = nullptr;
|
||||
std::size_t _ZN3sce4Json6String4nposE = static_cast<std::size_t>(-1);
|
||||
|
||||
void APS5_VABI _ZN3sce4Json6StringC1Ev(String* self) { Construct(*self, std::string_view{}); }
|
||||
@@ -3053,9 +3065,9 @@ const double* APS5_VABI _ZNK3sce4Json5Value7getRealEv(const Value* self) {
|
||||
const auto& value = Typed(self, TypeReal, &usedDefault);
|
||||
return usedDefault ? &_ZN3sce4Json5Value10s_nullrealE : &value.real;
|
||||
}
|
||||
const String* APS5_VABI _ZNK3sce4Json5Value9getStringEv(const Value* self) { return Typed(self, TypeString).string; }
|
||||
const Array* APS5_VABI _ZNK3sce4Json5Value8getArrayEv(const Value* self) { return Typed(self, TypeArray).array; }
|
||||
const Object* APS5_VABI _ZNK3sce4Json5Value9getObjectEv(const Value* self) { return Typed(self, TypeObject).object; }
|
||||
const String* APS5_VABI _ZNK3sce4Json5Value9getStringEv(const Value* self) { bool fallback = false; const auto& value = Typed(self, TypeString, &fallback); return fallback ? _ZN3sce4Json5Value12s_nullstringE : value.string; }
|
||||
const Array* APS5_VABI _ZNK3sce4Json5Value8getArrayEv(const Value* self) { bool fallback = false; const auto& value = Typed(self, TypeArray, &fallback); return fallback ? _ZN3sce4Json5Value11s_nullarrayE : value.array; }
|
||||
const Object* APS5_VABI _ZNK3sce4Json5Value9getObjectEv(const Value* self) { bool fallback = false; const auto& value = Typed(self, TypeObject, &fallback); return fallback ? _ZN3sce4Json5Value12s_nullobjectE : value.object; }
|
||||
std::size_t APS5_VABI _ZNK3sce4Json5Value5countEv(const Value* self) {
|
||||
const Node& n = NodeOf(*self);
|
||||
if (n.type == TypeArray) return n.array->items->size();
|
||||
|
||||
@@ -92,6 +92,9 @@ extern const bool _ZN3sce4Json5Value10s_nullboolE;
|
||||
extern const std::int64_t _ZN3sce4Json5Value13s_nullintegerE;
|
||||
extern const std::uint64_t _ZN3sce4Json5Value14s_nulluintegerE;
|
||||
extern const double _ZN3sce4Json5Value10s_nullrealE;
|
||||
extern String* _ZN3sce4Json5Value12s_nullstringE;
|
||||
extern Array* _ZN3sce4Json5Value11s_nullarrayE;
|
||||
extern Object* _ZN3sce4Json5Value12s_nullobjectE;
|
||||
|
||||
|
||||
int APS5_VABI _ZN3sce4Json12MemAllocatorD0Ev(void);
|
||||
|
||||
@@ -20,13 +20,23 @@ struct AllocationTrace {
|
||||
bool failOnce = false;
|
||||
Parameter* changeInput = nullptr;
|
||||
void* replacementContext = nullptr;
|
||||
std::size_t clearStringAt = 0;
|
||||
String* displacedString = nullptr;
|
||||
std::map<void*, std::size_t> live;
|
||||
std::vector<std::size_t> requests;
|
||||
std::vector<std::size_t> notifications;
|
||||
std::vector<unsigned> publishedDefaults;
|
||||
};
|
||||
static void* APS5_VABI AllocateTracked(void*, std::size_t bytes, void* context) {
|
||||
auto& trace = *static_cast<AllocationTrace*>(context);
|
||||
trace.requests.push_back(bytes);
|
||||
trace.publishedDefaults.push_back(unsigned(_ZN3sce4Json5Value12s_nullstringE != nullptr) |
|
||||
(unsigned(_ZN3sce4Json5Value11s_nullarrayE != nullptr) << 1) |
|
||||
(unsigned(_ZN3sce4Json5Value12s_nullobjectE != nullptr) << 2));
|
||||
if (trace.requests.size() == trace.clearStringAt) {
|
||||
trace.displacedString = _ZN3sce4Json5Value12s_nullstringE;
|
||||
_ZN3sce4Json5Value12s_nullstringE = nullptr;
|
||||
}
|
||||
if (trace.changeInput && trace.requests.size() == 1) {
|
||||
trace.changeInput->context = trace.replacementContext;
|
||||
trace.changeInput->bufferSize = 32768;
|
||||
@@ -65,6 +75,10 @@ static void CheckResources(AllocationTrace& trace) {
|
||||
const std::vector<std::size_t> requests{24, 8, 24, 8, 32, 48, 8, 32, 104, 32, 8, 8};
|
||||
Require(trace.requests.size() >= requests.size() && std::equal(requests.begin(), requests.end(), trace.requests.end() - requests.size()),
|
||||
"Initialization must allocate its actual context, defaults, fallback and synchronization handles in reference order");
|
||||
const std::vector<unsigned> publication{0, 0, 0, 1, 1, 1, 3, 3, 3, 7, 7, 7};
|
||||
Require(trace.publishedDefaults.size() >= publication.size() &&
|
||||
std::equal(publication.begin(), publication.end(), trace.publishedDefaults.end() - publication.size()),
|
||||
"Allocator callbacks must observe each default pointer only after its construction completes");
|
||||
bool contextFound = false;
|
||||
for (const auto& [memory, bytes] : trace.live) {
|
||||
if (bytes != 24) continue;
|
||||
@@ -77,6 +91,19 @@ static void CheckResources(AllocationTrace& trace) {
|
||||
const auto* string = _ZNK3sce4Json5Value9getStringEv(&null);
|
||||
const auto* array = _ZNK3sce4Json5Value8getArrayEv(&null);
|
||||
const auto* object = _ZNK3sce4Json5Value9getObjectEv(&null);
|
||||
Require(string == _ZN3sce4Json5Value12s_nullstringE && array == _ZN3sce4Json5Value11s_nullarrayE &&
|
||||
object == _ZN3sce4Json5Value12s_nullobjectE, "Getters must return the exported default pointers");
|
||||
auto* savedString = _ZN3sce4Json5Value12s_nullstringE;
|
||||
auto* savedArray = _ZN3sce4Json5Value11s_nullarrayE;
|
||||
auto* savedObject = _ZN3sce4Json5Value12s_nullobjectE;
|
||||
_ZN3sce4Json5Value12s_nullstringE = nullptr;
|
||||
_ZN3sce4Json5Value11s_nullarrayE = nullptr;
|
||||
_ZN3sce4Json5Value12s_nullobjectE = nullptr;
|
||||
Require(!_ZNK3sce4Json5Value9getStringEv(&null) && !_ZNK3sce4Json5Value8getArrayEv(&null) &&
|
||||
!_ZNK3sce4Json5Value9getObjectEv(&null), "Getters must observe writes to the exported pointers");
|
||||
_ZN3sce4Json5Value12s_nullstringE = savedString;
|
||||
_ZN3sce4Json5Value11s_nullarrayE = savedArray;
|
||||
_ZN3sce4Json5Value12s_nullobjectE = savedObject;
|
||||
Require(Owned(trace, string, 8) && Owned(trace, string->text, 24), "The default string must use the configured allocator");
|
||||
Require(Owned(trace, array, 8) && Owned(trace, array->items, 32) && Owned(trace, *reinterpret_cast<void**>(array->items), 48),
|
||||
"The default array must own its allocator-backed header and sentinel");
|
||||
@@ -167,6 +194,57 @@ static void CheckContextSnapshot() {
|
||||
Require(found && trace.live.size() == 12 && replacement.requests.empty(), "Context admission must cache allocator and user data before allocation and read the buffer setting afterward");
|
||||
Require(_ZN3sce4Json11Initializer9terminateEv(&initializer) == 0 && trace.live.empty() && replacement.live.empty(), "Termination must release the admitted context snapshot");
|
||||
}
|
||||
static void CheckReplacedDefaults() {
|
||||
AllocationTrace trace;
|
||||
TrackingAllocator allocator;
|
||||
Parameter parameter{&allocator, &trace, 16384, 2, {}};
|
||||
std::uint8_t initializer = 0;
|
||||
_ZN3sce4Json11InitializerC1Ev(&initializer);
|
||||
Require(_ZN3sce4Json11Initializer10initializeEPKNS0_14InitParameter2E(&initializer, reinterpret_cast<const InitParameter2*>(¶meter)) == 0,
|
||||
"Initialize before replacing exported defaults");
|
||||
auto* oldString = _ZN3sce4Json5Value12s_nullstringE;
|
||||
auto* oldArray = _ZN3sce4Json5Value11s_nullarrayE;
|
||||
auto* oldObject = _ZN3sce4Json5Value12s_nullobjectE;
|
||||
auto* replacementString = static_cast<String*>(AllocateTracked(&allocator, sizeof(String), &trace));
|
||||
auto* replacementArray = static_cast<Array*>(AllocateTracked(&allocator, sizeof(Array), &trace));
|
||||
auto* replacementObject = static_cast<Object*>(AllocateTracked(&allocator, sizeof(Object), &trace));
|
||||
_ZN3sce4Json6StringC1Ev(replacementString);
|
||||
_ZN3sce4Json5ArrayC1Ev(replacementArray);
|
||||
_ZN3sce4Json6ObjectC1Ev(replacementObject);
|
||||
_ZN3sce4Json6StringD1Ev(oldString);
|
||||
_ZN3sce4Json5ArrayD1Ev(oldArray);
|
||||
_ZN3sce4Json6ObjectD1Ev(oldObject);
|
||||
FreeTracked(&allocator, oldString, &trace);
|
||||
FreeTracked(&allocator, oldArray, &trace);
|
||||
FreeTracked(&allocator, oldObject, &trace);
|
||||
_ZN3sce4Json5Value12s_nullstringE = replacementString;
|
||||
_ZN3sce4Json5Value11s_nullarrayE = replacementArray;
|
||||
_ZN3sce4Json5Value12s_nullobjectE = replacementObject;
|
||||
Value null;
|
||||
_ZN3sce4Json5ValueC1Ev(&null);
|
||||
Require(_ZNK3sce4Json5Value9getStringEv(&null) == replacementString &&
|
||||
_ZNK3sce4Json5Value8getArrayEv(&null) == replacementArray &&
|
||||
_ZNK3sce4Json5Value9getObjectEv(&null) == replacementObject,
|
||||
"Getters must observe replacement pointers");
|
||||
_ZN3sce4Json5ValueD1Ev(&null);
|
||||
Require(_ZN3sce4Json11Initializer9terminateEv(&initializer) == 0 && trace.live.empty(),
|
||||
"Termination must destroy and release the replacement pointers");
|
||||
}
|
||||
static void CheckAdmissionReadsPublishedPointer() {
|
||||
AllocationTrace trace;
|
||||
trace.clearStringAt = 10;
|
||||
TrackingAllocator allocator;
|
||||
Parameter parameter{&allocator, &trace, 16384, 2, {}};
|
||||
std::uint8_t initializer = 0;
|
||||
_ZN3sce4Json11InitializerC1Ev(&initializer);
|
||||
Require(static_cast<unsigned>(_ZN3sce4Json11Initializer10initializeEPKNS0_14InitParameter2E(&initializer, reinterpret_cast<const InitParameter2*>(¶meter))) == 0x80848102 && !initializer,
|
||||
"Admission must read the exported pointer after allocator callbacks");
|
||||
Require(trace.displacedString && trace.live.size() == 2 && Owned(trace, trace.displacedString, sizeof(String)) &&
|
||||
Owned(trace, trace.displacedString->text, 24), "The displaced default must remain owned by its allocator");
|
||||
FreeTracked(&allocator, trace.displacedString->text, &trace);
|
||||
FreeTracked(&allocator, trace.displacedString, &trace);
|
||||
Require(trace.live.empty(), "Fixture cleanup must release the displaced allocation");
|
||||
}
|
||||
int main() {
|
||||
for (int budget = 0; budget <= 12; ++budget) {
|
||||
AllocationTrace trace;
|
||||
@@ -179,6 +257,8 @@ int main() {
|
||||
if (budget < 12) {
|
||||
Require(static_cast<unsigned>(result) == 0x80848102 && initializer == 0 && trace.live.empty(),
|
||||
"Every initialization allocation failure must report OOM, roll back ownership and leave retry legal");
|
||||
Require(!_ZN3sce4Json5Value12s_nullstringE && !_ZN3sce4Json5Value11s_nullarrayE && !_ZN3sce4Json5Value12s_nullobjectE,
|
||||
"Initialization rollback must clear the exported default pointers");
|
||||
Require((budget == 0) == trace.notifications.empty(), "Only the first context-allocation failure omits notification");
|
||||
trace.budget = -1;
|
||||
Require(_ZN3sce4Json11Initializer10initializeEPKNS0_14InitParameter2E(&initializer, reinterpret_cast<const InitParameter2*>(¶meter)) == 0,
|
||||
@@ -192,8 +272,12 @@ int main() {
|
||||
parameter.context = &unrelated;
|
||||
Require(_ZN3sce4Json11Initializer9terminateEv(&initializer) == 0 && initializer == 0 && trace.live.empty() && unrelated.live.empty(),
|
||||
"Termination must release the snapshotted allocation context and every resource");
|
||||
Require(!_ZN3sce4Json5Value12s_nullstringE && !_ZN3sce4Json5Value11s_nullarrayE && !_ZN3sce4Json5Value12s_nullobjectE,
|
||||
"Termination must clear the exported default pointers");
|
||||
}
|
||||
CheckSingleFailures();
|
||||
CheckContextSnapshot();
|
||||
CheckReplacedDefaults();
|
||||
CheckAdmissionReadsPublishedPointer();
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user