Files
AnyPS5/core/libs/tests/GuestNpSnsFacebookDialog.cpp
T
XairRrR 1e26b92ae1 fix(libSceNpSnsFacebookDialog): keep a terminated dialog terminated during Open and Close
sceNpSnsFacebookDialogOpen and sceNpSnsFacebookDialogClose read the
dialog status, checked it, and then stored FINISHED in a separate step.
If another thread called sceNpSnsFacebookDialogTerminate between the
read and the store, Terminate returned 0 and set the status to NONE,
and then Open or Close wrote FINISHED over it. The library was left
looking initialized after it had been terminated:
sceNpSnsFacebookDialogGetStatus returned FINISHED and the next
sceNpSnsFacebookDialogInitialize failed with ALREADY_INITIALIZED.

Open and Close now move the status to FINISHED with a compare-exchange
loop that repeats the checks against the value it replaces, so a
concurrent Terminate either happens first, making the call return
NOT_INITIALIZED, or happens after, leaving the status at NONE. Open
still offers the PSN feature notice only after a successful transition.

guest_np_sns_facebook_dialog gains two cases that race Open and Close
against Terminate for 200000 rounds each and require the status to be
NONE after every round.

AI-assisted: yes
2026-11-04 00:11:47 +01:00

137 lines
5.7 KiB
C++

#include "prx/libSceNpSnsFacebookDialog/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <atomic>
#include <cstdint>
#include <cstdlib>
#include <thread>
namespace {
void Require(bool value) { if (!value) std::abort(); }
constexpr int kStatusNone = 0;
constexpr int kStatusInitialized = 1;
constexpr int kStatusFinished = 3;
constexpr int kErrNotInitialized = static_cast<int>(0x80B80003);
constexpr int kErrAlreadyInitialized = static_cast<int>(0x80B80004);
constexpr int kErrNotFinished = static_cast<int>(0x80B80005);
constexpr int kErrArgNull = static_cast<int>(0x80B8000D);
constexpr int kResultUserCanceled = 1;
constexpr int kRaceRounds = 200000;
template <typename Finish>
void RequireTerminateWins(Finish finish) {
std::atomic<int> round{0};
std::atomic<int> done{0};
std::thread terminator([&] {
for (int i = 1; i <= kRaceRounds; ++i) {
while (round.load() != i) {}
sceNpSnsFacebookDialogTerminate();
done.fetch_add(1);
}
});
for (int i = 1; i <= kRaceRounds; ++i) {
Require(sceNpSnsFacebookDialogInitialize() == 0);
round.store(i);
finish();
while (done.load() != i) {}
Require(sceNpSnsFacebookDialogGetStatus() == kStatusNone);
}
terminator.join();
}
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices() {
std::uint64_t param = 0;
ModalDialogSetPresenter_nid_postfix(true);
Require(sceNpSnsFacebookDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpSnsFacebookDialogOpen(&param) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpSnsFacebookDialogOpen(nullptr) == kErrArgNull);
Require(!PsnNoticeShown());
Require(sceNpSnsFacebookDialogOpen(&param) == 0);
Require(PsnNoticeShown());
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(sceNpSnsFacebookDialogTerminate() == 0);
}
}
int main() {
std::int64_t param = 0;
std::int32_t result[2] = {-1, -1};
Require(sceNpSnsFacebookDialogTerminate() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogOpen(nullptr) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogOpen(&param) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogClose() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetResult(nullptr) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetResult(result) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogInitialize() == 0);
Require(sceNpSnsFacebookDialogInitialize() == kErrAlreadyInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusInitialized);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusInitialized);
Require(sceNpSnsFacebookDialogOpen(nullptr) == kErrArgNull);
Require(sceNpSnsFacebookDialogGetResult(result) == kErrNotFinished);
Require(sceNpSnsFacebookDialogOpen(&param) == 0);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusFinished);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusFinished);
Require(sceNpSnsFacebookDialogGetResult(nullptr) == kErrArgNull);
Require(sceNpSnsFacebookDialogGetResult(result) == 0);
Require(result[0] == kResultUserCanceled);
Require(result[1] == -1);
Require(sceNpSnsFacebookDialogClose() == 0);
Require(sceNpSnsFacebookDialogTerminate() == 0);
Require(sceNpSnsFacebookDialogTerminate() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogOpen(nullptr) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogOpen(&param) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogClose() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetResult(nullptr) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetResult(result) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogInitialize() == 0);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusInitialized);
Require(sceNpSnsFacebookDialogClose() == 0);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusFinished);
result[0] = -1;
Require(sceNpSnsFacebookDialogGetResult(result) == 0);
Require(result[0] == kResultUserCanceled);
Require(sceNpSnsFacebookDialogTerminate() == 0);
Require(sceNpSnsFacebookDialogTerminate() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogOpen(nullptr) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogOpen(&param) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogClose() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetResult(nullptr) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetResult(result) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusNone);
RequireNotices();
RequireTerminateWins([&] { sceNpSnsFacebookDialogOpen(&param); });
RequireTerminateWins([] { sceNpSnsFacebookDialogClose(); });
}