Store: Fix race condition causing crashes if looking at another game before an icon finishes downloading

This commit is contained in:
Henrik Rydgård 2023-09-20 21:45:03 +02:00
parent 65b995ac6c
commit 2648cd0eee
4 changed files with 13 additions and 7 deletions

View file

@ -228,7 +228,7 @@ bool IconCache::MarkPending(const std::string &key) {
return true; return true;
} }
void IconCache::Cancel(const std::string &key) { void IconCache::CancelPending(const std::string &key) {
std::unique_lock<std::mutex> lock(lock_); std::unique_lock<std::mutex> lock(lock_);
pending_.erase(key); pending_.erase(key);
} }
@ -266,6 +266,7 @@ Draw::Texture *IconCache::BindIconTexture(UIContext *context, const std::string
return nullptr; return nullptr;
} }
// TODO: Cut down on how long we're holding this lock here.
std::unique_lock<std::mutex> lock(lock_); std::unique_lock<std::mutex> lock(lock_);
auto iter = cache_.find(key); auto iter = cache_.find(key);
if (iter == cache_.end()) { if (iter == cache_.end()) {

View file

@ -36,7 +36,7 @@ public:
// It's okay to call these from any thread. // It's okay to call these from any thread.
bool MarkPending(const std::string &key); // returns false if already pending or loaded bool MarkPending(const std::string &key); // returns false if already pending or loaded
void Cancel(const std::string &key); void CancelPending(const std::string &key);
bool InsertIcon(const std::string &key, IconFormat format, std::string &&pngData); bool InsertIcon(const std::string &key, IconFormat format, std::string &&pngData);
bool GetDimensions(const std::string &key, int *width, int *height); bool GetDimensions(const std::string &key, int *width, int *height);
bool Contains(const std::string &key); bool Contains(const std::string &key);

View file

@ -396,6 +396,8 @@ void SasInstance::GetDebugText(char *text, size_t bufsize) {
indicator = " (BAD!)"; indicator = " (BAD!)";
} }
break; break;
default:
break;
} }
p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " %d: Pitch %04x L/R,FX: %d,%d|%d,%d VAG: %08x:%d:%08x%s Height:%d%%\n", i, p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " %d: Pitch %04x L/R,FX: %d,%d|%d,%d VAG: %08x:%d:%08x%s Height:%d%%\n", i,
voices[i].pitch, voices[i].volumeLeft, voices[i].volumeRight, voices[i].effectLeft, voices[i].effectRight, voices[i].pitch, voices[i].volumeLeft, voices[i].volumeRight, voices[i].effectLeft, voices[i].effectRight,

View file

@ -63,26 +63,29 @@ public:
if (useIconCache && g_iconCache.MarkPending(path_)) { if (useIconCache && g_iconCache.MarkPending(path_)) {
const char *acceptMime = "image/png, image/jpeg, image/*; q=0.9, */*; q=0.8"; const char *acceptMime = "image/png, image/jpeg, image/*; q=0.9, */*; q=0.8";
requestManager_->StartDownloadWithCallback(path_, Path(), http::ProgressBarMode::DELAYED, [&](http::Request &download) { requestManager_->StartDownloadWithCallback(path_, Path(), http::ProgressBarMode::DELAYED, [](http::Request &download) {
// Can't touch 'this' in this function! Don't use captures!
std::string path = download.url();
if (download.ResultCode() == 200) { if (download.ResultCode() == 200) {
std::string data; std::string data;
download.buffer().TakeAll(&data); download.buffer().TakeAll(&data);
if (!data.empty()) { if (!data.empty()) {
g_iconCache.InsertIcon(path_, IconFormat::PNG, std::move(data)); g_iconCache.InsertIcon(path, IconFormat::PNG, std::move(data));
} else { } else {
g_iconCache.Cancel(path_); g_iconCache.CancelPending(path);
} }
} else { } else {
g_iconCache.Cancel(path_); g_iconCache.CancelPending(path);
} }
}, acceptMime); }, acceptMime);
} }
} }
~HttpImageFileView() { ~HttpImageFileView() {
if (download_) if (download_) {
download_->Cancel(); download_->Cancel();
} }
}
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
void Draw(UIContext &dc) override; void Draw(UIContext &dc) override;