diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index 5c485750..145b689f 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -562,7 +562,7 @@ void DoSavestate(Savestate* file)
         file->Bool32(&poly->IsShadowMask);
         file->Bool32(&poly->IsShadow);
 
-        if (file->IsAtleastVersion(4, 1))
+        if (file->IsAtLeastVersion(4, 1))
             file->Var32((u32*)&poly->Type);
         else
             poly->Type = 0;
diff --git a/src/NDS.cpp b/src/NDS.cpp
index b5c00db1..e37a1944 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -815,7 +815,10 @@ bool DoSavestate(Savestate* file)
         u32 console;
         file->Var32(&console);
         if (console != ConsoleType)
+        {
+            Log(LogLevel::Error, "savestate: Expected console type %d, got console type %d. cannot load.\n", ConsoleType, console);
             return false;
+        }
     }
 
     file->VarArray(MainRAM, MainRAMMaxSize);
@@ -870,7 +873,11 @@ bool DoSavestate(Savestate* file)
 
     file->VarArray(DMA9Fill, 4*sizeof(u32));
 
-    if (!DoSavestate_Scheduler(file)) return false;
+    if (!DoSavestate_Scheduler(file))
+    {
+        Platform::Log(Platform::LogLevel::Error, "savestate: failed to %s scheduler state\n", file->Saving ? "save" : "load");
+        return false;
+    }
     file->Var32(&SchedListMask);
     file->Var64(&ARM9Timestamp);
     file->Var64(&ARM9Target);
@@ -937,6 +944,8 @@ bool DoSavestate(Savestate* file)
     }
 #endif
 
+    file->Finish();
+
     return true;
 }
 
diff --git a/src/Savestate.cpp b/src/Savestate.cpp
index 0aa0ba37..546c16e0 100644
--- a/src/Savestate.cpp
+++ b/src/Savestate.cpp
@@ -17,12 +17,16 @@
 */
 
 #include <stdio.h>
+#include <cassert>
+#include <cstring>
 #include "Savestate.h"
 #include "Platform.h"
 
 using Platform::Log;
 using Platform::LogLevel;
 
+static const char* SAVESTATE_MAGIC = "MELN";
+
 /*
     Savestate format
 
@@ -46,230 +50,148 @@ using Platform::LogLevel;
     * different minor means adjustments may have to be made
 */
 
-// TODO: buffering system! or something of that sort
-// repeated fread/fwrite is slow on Switch
-
-Savestate::Savestate(const std::string& filename, bool save)
+Savestate::Savestate(void *buffer, u32 size, bool save) :
+    Error(false),
+    Saving(save),
+    CurSection(NO_SECTION),
+    buffer(static_cast<u8 *>(buffer)),
+    buffer_offset(0),
+    buffer_length(size),
+    buffer_owned(false),
+    finished(false)
 {
-    const char* magic = "MELN";
-
-    Error = false;
-
-    if (save)
+    if (Saving)
     {
-        Saving = true;
-        file = Platform::OpenLocalFile(filename, "wb");
-        if (!file)
-        {
-            Log(LogLevel::Error, "savestate: file %s doesn't exist\n", filename.c_str());
-            Error = true;
-            return;
-        }
-
-        VersionMajor = SAVESTATE_MAJOR;
-        VersionMinor = SAVESTATE_MINOR;
-
-        fwrite(magic, 4, 1, file);
-        fwrite(&VersionMajor, 2, 1, file);
-        fwrite(&VersionMinor, 2, 1, file);
-        fseek(file, 8, SEEK_CUR); // length to be fixed later
+        WriteSavestateHeader();
     }
     else
     {
-        Saving = false;
-        file = Platform::OpenFile(filename, "rb");
-        if (!file)
+        // Ensure that the file starts with "MELN"
+        u32 read_magic = 0;
+        Var32(&read_magic);
+
+        if (read_magic != *((u32*)SAVESTATE_MAGIC))
         {
-            Log(LogLevel::Error, "savestate: file %s doesn't exist\n", filename.c_str());
+            Log(LogLevel::Error, "savestate: expected magic number %#08x (%s), got %#08x\n",
+                *((u32*)SAVESTATE_MAGIC),
+                SAVESTATE_MAGIC,
+                read_magic
+            );
             Error = true;
             return;
         }
 
-        u32 len;
-        fseek(file, 0, SEEK_END);
-        len = (u32)ftell(file);
-        fseek(file, 0, SEEK_SET);
-
-        u32 buf = 0;
-
-        fread(&buf, 4, 1, file);
-        if (buf != ((u32*)magic)[0])
+        u16 major = 0;
+        Var16(&major);
+        if (major != SAVESTATE_MAJOR)
         {
-            Log(LogLevel::Error, "savestate: invalid magic %08X\n", buf);
+            Log(LogLevel::Error, "savestate: bad version major %d, expecting %d\n", major, SAVESTATE_MAJOR);
             Error = true;
             return;
         }
 
-        VersionMajor = 0;
-        VersionMinor = 0;
-
-        fread(&VersionMajor, 2, 1, file);
-        if (VersionMajor != SAVESTATE_MAJOR)
+        u16 minor = 0;
+        Var16(&minor);
+        if (minor > SAVESTATE_MINOR)
         {
-            Log(LogLevel::Error, "savestate: bad version major %d, expecting %d\n", VersionMajor, SAVESTATE_MAJOR);
+            Log(LogLevel::Error, "savestate: state from the future, %d > %d\n", minor, SAVESTATE_MINOR);
             Error = true;
             return;
         }
 
-        fread(&VersionMinor, 2, 1, file);
-        if (VersionMinor > SAVESTATE_MINOR)
+        u32 read_length = 0;
+        Var32(&read_length);
+        if (read_length != buffer_length)
         {
-            Log(LogLevel::Error, "savestate: state from the future, %d > %d\n", VersionMinor, SAVESTATE_MINOR);
+            Log(LogLevel::Error, "savestate: expected a length of %d, got %d\n", buffer_length, read_length);
             Error = true;
             return;
         }
 
-        buf = 0;
-        fread(&buf, 4, 1, file);
-        if (buf != len)
-        {
-            Log(LogLevel::Error, "savestate: bad length %d\n", buf);
-            Error = true;
-            return;
-        }
+        // The next 4 bytes are reserved
+        buffer_offset += 4;
+    }
+}
 
-        fseek(file, 4, SEEK_CUR);
+
+Savestate::Savestate(u32 initial_size) :
+    Error(false),
+    Saving(true), // Can't load from an empty buffer
+    CurSection(NO_SECTION),
+    buffer(nullptr),
+    buffer_offset(0),
+    buffer_length(initial_size),
+    buffer_owned(true),
+    finished(false)
+{
+    buffer = static_cast<u8 *>(malloc(buffer_length));
+
+    if (buffer == nullptr)
+    {
+        Log(LogLevel::Error, "savestate: failed to allocate %d bytes\n", buffer_length);
+        Error = true;
+        return;
     }
 
-    CurSection = -1;
+    WriteSavestateHeader();
 }
 
 Savestate::~Savestate()
 {
-    if (Error) return;
-
-    if (Saving)
-    {
-        if (CurSection != 0xFFFFFFFF)
-        {
-            u32 pos = (u32)ftell(file);
-            fseek(file, CurSection+4, SEEK_SET);
-
-            u32 len = pos - CurSection;
-            fwrite(&len, 4, 1, file);
-
-            fseek(file, pos, SEEK_SET);
-        }
-
-        fseek(file, 0, SEEK_END);
-        u32 len = (u32)ftell(file);
-        fseek(file, 8, SEEK_SET);
-        fwrite(&len, 4, 1, file);
+    if (Saving && !finished && !buffer_owned && !Error)
+    { // If we haven't finished saving, and there hasn't been an error...
+        Finish();
+        // No need to close the active section for an owned buffer,
+        // it's about to be thrown out.
     }
 
-    if (file) fclose(file);
+    if (buffer_owned)
+    {
+        free(buffer);
+    }
 }
 
 void Savestate::Section(const char* magic)
 {
-    if (Error) return;
+    if (Error || finished) return;
 
     if (Saving)
     {
-        if (CurSection != 0xFFFFFFFF)
+        // Go back to the current section's header and write the length
+        CloseCurrentSection();
+
+        CurSection = buffer_offset;
+
+        // Write the new section's magic number
+        VarArray((void*)magic, 4);
+
+        // The next 4 bytes are the length, which we'll come back to later.
+        u32 zero = 0;
+        Var32(&zero);
+
+        // The 8 bytes afterward are reserved, so we skip them.
+        Var32(&zero);
+        Var32(&zero);
+    }
+    else
+    {
+        u32 section_offset = FindSection(magic);
+
+        if (section_offset != NO_SECTION)
         {
-            u32 pos = (u32)ftell(file);
-            fseek(file, CurSection+4, SEEK_SET);
-
-            u32 len = pos - CurSection;
-            fwrite(&len, 4, 1, file);
-
-            fseek(file, pos, SEEK_SET);
+            buffer_offset = section_offset;
         }
-
-        CurSection = (u32)ftell(file);
-
-        fwrite(magic, 4, 1, file);
-        fseek(file, 12, SEEK_CUR);
-    }
-    else
-    {
-        fseek(file, 0x10, SEEK_SET);
-
-        for (;;)
+        else
         {
-            u32 buf = 0;
-
-            fread(&buf, 4, 1, file);
-            if (buf != ((u32*)magic)[0])
-            {
-                if (buf == 0)
-                {
-                    Log(LogLevel::Error, "savestate: section %s not found. blarg\n", magic);
-                    return;
-                }
-
-                buf = 0;
-                fread(&buf, 4, 1, file);
-                fseek(file, buf-8, SEEK_CUR);
-                continue;
-            }
-
-            fseek(file, 12, SEEK_CUR);
-            break;
+            Log(LogLevel::Error, "savestate: section %s not found. blarg\n", magic);
+            Error = true;
         }
     }
 }
 
-void Savestate::Var8(u8* var)
-{
-    if (Error) return;
-
-    if (Saving)
-    {
-        fwrite(var, 1, 1, file);
-    }
-    else
-    {
-        fread(var, 1, 1, file);
-    }
-}
-
-void Savestate::Var16(u16* var)
-{
-    if (Error) return;
-
-    if (Saving)
-    {
-        fwrite(var, 2, 1, file);
-    }
-    else
-    {
-        fread(var, 2, 1, file);
-    }
-}
-
-void Savestate::Var32(u32* var)
-{
-    if (Error) return;
-
-    if (Saving)
-    {
-        fwrite(var, 4, 1, file);
-    }
-    else
-    {
-        fread(var, 4, 1, file);
-    }
-}
-
-void Savestate::Var64(u64* var)
-{
-    if (Error) return;
-
-    if (Saving)
-    {
-        fwrite(var, 8, 1, file);
-    }
-    else
-    {
-        fread(var, 8, 1, file);
-    }
-}
-
 void Savestate::Bool32(bool* var)
 {
-    // for compability
+    // for compatibility
     if (Saving)
     {
         u32 val = *var;
@@ -285,14 +207,175 @@ void Savestate::Bool32(bool* var)
 
 void Savestate::VarArray(void* data, u32 len)
 {
-    if (Error) return;
+    if (Error || finished) return;
+
+    assert(buffer_offset <= buffer_length);
 
     if (Saving)
     {
-        fwrite(data, len, 1, file);
+        if (buffer_offset + len > buffer_length)
+        { // If writing the given data would take us past the buffer's end...
+            Log(LogLevel::Warn, "savestate: %u-byte write would exceed %u-byte savestate buffer\n", len, buffer_length);
+
+            if (!(buffer_owned && Resize(buffer_length * 2 + len)))
+            { // If we're not allowed to resize this buffer, or if we are but failed...
+                Log(LogLevel::Error, "savestate: Failed to write %d bytes to savestate\n", len);
+                Error = true;
+                return;
+            }
+            // The buffer's length is doubled, plus however much memory is needed for this write.
+            // This way we can write the data and reduce the chance of needing to resize again.
+        }
+
+        memcpy(buffer + buffer_offset, data, len);
     }
     else
     {
-        fread(data, len, 1, file);
+        if (buffer_offset + len > buffer_length)
+        { // If reading the requested amount of data would take us past the buffer's edge...
+            Log(LogLevel::Error, "savestate: %u-byte read would exceed %u-byte savestate buffer\n", len, buffer_length);
+            Error = true;
+            return;
+
+            // Can't realloc here.
+            // Not only do we not own the buffer pointer (when loading a state),
+            // but we can't magically make the desired data appear.
+        }
+
+        memcpy(data, buffer + buffer_offset, len);
+    }
+
+    buffer_offset += len;
+}
+
+void Savestate::Finish()
+{
+    if (Error || finished) return;
+    CloseCurrentSection();
+    WriteStateLength();
+    finished = true;
+}
+
+void Savestate::Rewind(bool save)
+{
+    Error = false;
+    Saving = save;
+    CurSection = NO_SECTION;
+
+    buffer_offset = 0;
+    finished = false;
+}
+
+void Savestate::CloseCurrentSection()
+{
+    if (CurSection != NO_SECTION && !finished)
+    { // If we're in the middle of writing a section...
+
+        // Go back to the section's header
+        // Get the length of the section we've written thus far
+        u32 section_length = buffer_offset - CurSection;
+
+        // Write the length in the section's header
+        // (specifically the first 4 bytes after the magic number)
+        memcpy(buffer + CurSection + 4, &section_length, sizeof(section_length));
+
+        CurSection = NO_SECTION;
     }
 }
+
+bool Savestate::Resize(u32 new_length)
+{
+    if (!buffer_owned)
+    { // If we're not allowed to resize this buffer...
+        Log(LogLevel::Error, "savestate: Buffer is externally-owned, cannot resize it\n");
+        return false;
+    }
+
+    u32 old_length = buffer_length;
+    void* resized = realloc(buffer, new_length);
+    if (!resized)
+    { // If the buffer couldn't be expanded...
+        Log(LogLevel::Error, "savestate: Failed to resize owned savestate buffer from %dB to %dB\n", old_length, new_length);
+        return false;
+    }
+
+    u32 length_diff = new_length - old_length;
+    buffer = static_cast<u8 *>(resized);
+    buffer_length = new_length;
+
+    Log(LogLevel::Debug, "savestate: Expanded %uB savestate buffer to %uB\n", old_length, new_length);
+    // Zero out the newly-allocated memory (to ensure we don't introduce a security hole)
+    memset(buffer + old_length, 0, length_diff);
+    return true;
+}
+
+void Savestate::WriteSavestateHeader()
+{
+    // The magic number
+    VarArray((void *) SAVESTATE_MAGIC, 4);
+
+    // The major and minor versions
+    u16 major = SAVESTATE_MAJOR;
+    Var16(&major);
+
+    u16 minor = SAVESTATE_MINOR;
+    Var16(&minor);
+
+    // The next 4 bytes are the file's length, which will be filled in at the end
+    u32 zero = 0;
+    Var32(&zero);
+
+    // The following 4 bytes are reserved
+    Var32(&zero);
+}
+
+void Savestate::WriteStateLength()
+{
+    // Not to be confused with the buffer length.
+    // The buffer might not be full,
+    // so we don't want to write out the extra stuff.
+    u32 state_length = buffer_offset;
+
+    // Write the length in the header
+    memcpy(buffer + 0x08, &state_length, sizeof(state_length));
+}
+
+u32 Savestate::FindSection(const char* magic) const
+{
+    if (!magic) return NO_SECTION;
+
+    // Start looking at the savestate's beginning, right after its global header
+    // (we can't start from the current offset because then we'd lose the ability to rearrange sections)
+
+    for (u32 offset = 0x10; offset < buffer_length;)
+    { // Until we've found the desired section...
+
+        // Get this section's magic number
+        char read_magic[4] = {0};
+        memcpy(read_magic, buffer + offset, sizeof(read_magic));
+
+        if (memcmp(read_magic, magic, sizeof(read_magic)) == 0)
+        { // If this is the right section...
+            return offset + 16; // ...return the offset of the first byte of the section after the header
+        }
+
+        // Haven't found our section yet. Let's move on to the next one.
+
+        u32 section_length_offset = offset + sizeof(read_magic);
+        if (section_length_offset >= buffer_length)
+        { // If trying to read the section length would take us past the file's end...
+            break;
+        }
+
+        // First we need to find out how big this section is...
+        u32 section_length = 0;
+        memcpy(&section_length, buffer + section_length_offset, sizeof(section_length));
+
+        // ...then skip it. (The section length includes the 16-byte header.)
+        offset += section_length;
+    }
+
+    // We've reached the end of the file without finding the requested section...
+    Log(LogLevel::Error, "savestate: section %s not found. blarg\n", magic);
+    return NO_SECTION;
+}
\ No newline at end of file
diff --git a/src/Savestate.h b/src/Savestate.h
index a2216ce2..0aef517e 100644
--- a/src/Savestate.h
+++ b/src/Savestate.h
@@ -19,6 +19,7 @@
 #ifndef SAVESTATE_H
 #define SAVESTATE_H
 
+#include <cstring>
 #include <string>
 #include <stdio.h>
 #include "types.h"
@@ -29,37 +30,92 @@
 class Savestate
 {
 public:
-    Savestate(const std::string& filename, bool save);
+    static constexpr u32 DEFAULT_SIZE = 32 * 1024 * 1024; // 32 MB
+    Savestate(void* buffer, u32 size, bool save);
+    explicit Savestate(u32 initial_size = DEFAULT_SIZE);
+
     ~Savestate();
 
     bool Error;
 
     bool Saving;
-    u32 VersionMajor;
-    u32 VersionMinor;
 
     u32 CurSection;
 
     void Section(const char* magic);
 
-    void Var8(u8* var);
-    void Var16(u16* var);
-    void Var32(u32* var);
-    void Var64(u64* var);
+    void Var8(u8* var)
+    {
+        VarArray(var, sizeof(*var));
+    }
+
+    void Var16(u16* var)
+    {
+        VarArray(var, sizeof(*var));
+    }
+
+    void Var32(u32* var)
+    {
+        VarArray(var, sizeof(*var));
+    }
+
+    void Var64(u64* var)
+    {
+        VarArray(var, sizeof(*var));
+    }
 
     void Bool32(bool* var);
 
     void VarArray(void* data, u32 len);
 
-    bool IsAtleastVersion(u32 major, u32 minor)
+    void Finish();
+
+    // TODO rewinds the stream
+    void Rewind(bool save);
+
+    bool IsAtLeastVersion(u32 major, u32 minor)
     {
-        if (VersionMajor > major) return true;
-        if (VersionMajor == major && VersionMinor >= minor) return true;
+        u16 major_version = MajorVersion();
+        if (MajorVersion() > major) return true;
+        if (major_version == major && MinorVersion() >= minor) return true;
         return false;
     }
 
+    void* Buffer() { return buffer; }
+    [[nodiscard]] const void* Buffer() const { return buffer; }
+
+    [[nodiscard]] u32 BufferLength() const { return buffer_length; }
+
+    [[nodiscard]] u32 Length() const { return buffer_offset; }
+
+    [[nodiscard]] u16 MajorVersion() const
+    {
+        // major version is stored at offset 0x04
+        u16 major = 0;
+        memcpy(&major, buffer + 0x04, sizeof(major));
+        return major;
+    }
+
+    [[nodiscard]] u16 MinorVersion() const
+    {
+        // minor version is stored at offset 0x06
+        u16 minor = 0;
+        memcpy(&minor, buffer + 0x06, sizeof(minor));
+        return minor;
+    }
+
 private:
-    FILE* file;
+    static constexpr u32 NO_SECTION = 0xffffffff;
+    void CloseCurrentSection();
+    bool Resize(u32 new_length);
+    void WriteSavestateHeader();
+    void WriteStateLength();
+    u32 FindSection(const char* magic) const;
+    u8* buffer;
+    u32 buffer_offset;
+    u32 buffer_length;
+    bool buffer_owned;
+    bool finished;
 };
 
 #endif // SAVESTATE_H
diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp
index 95337e11..80f46525 100644
--- a/src/frontend/qt_sdl/ROMManager.cpp
+++ b/src/frontend/qt_sdl/ROMManager.cpp
@@ -21,6 +21,7 @@
 
 #include <string>
 #include <utility>
+#include <fstream>
 
 #include <zstd.h>
 #ifdef ARCHIVE_SUPPORT_ENABLED
@@ -52,6 +53,7 @@ std::string BaseGBAAssetName = "";
 SaveManager* NDSSave = nullptr;
 SaveManager* GBASave = nullptr;
 
+std::unique_ptr<Savestate> BackupState = nullptr;
 bool SavestateLoaded = false;
 std::string PreviousSaveFile = "";
 
@@ -304,35 +306,62 @@ bool SavestateExists(int slot)
 
 bool LoadState(const std::string& filename)
 {
-    // backup
-    Savestate* backup = new Savestate("timewarp.mln", true);
-    NDS::DoSavestate(backup);
-    delete backup;
-
-    bool failed = false;
-
-    Savestate* state = new Savestate(filename, false);
-    if (state->Error)
-    {
-        delete state;
-
-        // current state might be crapoed, so restore from sane backup
-        state = new Savestate("timewarp.mln", false);
-        failed = true;
+    FILE* file = fopen(filename.c_str(), "rb");
+    if (file == nullptr)
+    { // If we couldn't open the state file...
+        Platform::Log(Platform::LogLevel::Error, "Failed to open state file \"%s\"\n", filename.c_str());
+        return false;
     }
 
-    bool res = NDS::DoSavestate(state);
-    delete state;
-
-    if (!res)
-    {
-        failed = true;
-        state = new Savestate("timewarp.mln", false);
-        NDS::DoSavestate(state);
-        delete state;
+    std::unique_ptr<Savestate> backup = std::make_unique<Savestate>(Savestate::DEFAULT_SIZE);
+    if (backup->Error)
+    { // If we couldn't allocate memory for the backup...
+        Platform::Log(Platform::LogLevel::Error, "Failed to allocate memory for state backup\n");
+        fclose(file);
+        return false;
     }
 
-    if (failed) return false;
+    if (!NDS::DoSavestate(backup.get()) || backup->Error)
+    { // Back up the emulator's state. If that failed...
+        Platform::Log(Platform::LogLevel::Error, "Failed to back up state, aborting load (from \"%s\")\n", filename.c_str());
+        fclose(file);
+        return false;
+    }
+    // We'll store the backup once we're sure that the state was loaded.
+    // Now that we know the file and backup are both good, let's load the new state.
+
+    // Get the size of the file that we opened
+    if (fseek(file, 0, SEEK_END) != 0)
+    {
+        Platform::Log(Platform::LogLevel::Error, "Failed to seek to end of state file \"%s\"\n", filename.c_str());
+        fclose(file);
+        return false;
+    }
+    size_t size = ftell(file);
+    rewind(file); // reset the filebuf's position
+
+    // Allocate exactly as much memory as we need for the savestate
+    std::vector<u8> buffer(size);
+    if (fread(buffer.data(), size, 1, file) == 0)
+    { // Read the state file into the buffer. If that failed...
+        Platform::Log(Platform::LogLevel::Error, "Failed to read %u-byte state file \"%s\"\n", size, filename.c_str());
+        fclose(file);
+        return false;
+    }
+    fclose(file); // done with the file now
+
+    // Get ready to load the state from the buffer into the emulator
+    std::unique_ptr<Savestate> state = std::make_unique<Savestate>(buffer.data(), size, false);
+
+    if (!NDS::DoSavestate(state.get()) || state->Error)
+    { // If we couldn't load the savestate from the buffer...
+        Platform::Log(Platform::LogLevel::Error, "Failed to load state file \"%s\" into emulator\n", filename.c_str());
+        return false;
+    }
+
+    // The backup was made and the state was loaded, so we can store the backup now.
+    BackupState = std::move(backup); // This will clean up any existing backup
+    assert(backup == nullptr);
 
     if (Config::SavestateRelocSRAM && NDSSave)
     {
@@ -351,15 +380,41 @@ bool LoadState(const std::string& filename)
 
 bool SaveState(const std::string& filename)
 {
-    Savestate* state = new Savestate(filename, true);
-    if (state->Error)
-    {
-        delete state;
+    FILE* file = fopen(filename.c_str(), "wb");
+
+    if (file == nullptr)
+    { // If the file couldn't be opened...
         return false;
     }
 
-    NDS::DoSavestate(state);
-    delete state;
+    Savestate state;
+    if (state.Error)
+    { // If there was an error creating the state (and allocating its memory)...
+        fclose(file);
+        return false;
+    }
+
+    // Write the savestate to the in-memory buffer
+    NDS::DoSavestate(&state);
+
+    if (state.Error)
+    {
+        fclose(file);
+        return false;
+    }
+
+    if (fwrite(state.Buffer(), state.Length(), 1, file) == 0)
+    { // Write the Savestate buffer to the file. If that fails...
+        Platform::Log(Platform::Error,
+            "Failed to write %d-byte savestate to %s\n",
+            state.Length(),
+            filename.c_str()
+        );
+        fclose(file);
+        return false;
+    }
+
+    fclose(file);
 
     if (Config::SavestateRelocSRAM && NDSSave)
     {
@@ -374,14 +429,14 @@ bool SaveState(const std::string& filename)
 
 void UndoStateLoad()
 {
-    if (!SavestateLoaded) return;
+    if (!SavestateLoaded || !BackupState) return;
 
+    // Rewind the backup state and put it in load mode
+    BackupState->Rewind(false);
     // pray that this works
     // what do we do if it doesn't???
     // but it should work.
-    Savestate* backup = new Savestate("timewarp.mln", false);
-    NDS::DoSavestate(backup);
-    delete backup;
+    NDS::DoSavestate(BackupState.get());
 
     if (NDSSave && (!PreviousSaveFile.empty()))
     {
@@ -514,6 +569,14 @@ u32 DecompressROM(const u8* inContent, const u32 inSize, u8** outContent)
     return realSize;
 }
 
+void ClearBackupState()
+{
+    if (BackupState != nullptr)
+    {
+        BackupState = nullptr;
+    }
+}
+
 bool LoadROM(QStringList filepath, bool reset)
 {
     if (filepath.empty()) return false;
diff --git a/src/frontend/qt_sdl/ROMManager.h b/src/frontend/qt_sdl/ROMManager.h
index efaed36b..1ec0fe51 100644
--- a/src/frontend/qt_sdl/ROMManager.h
+++ b/src/frontend/qt_sdl/ROMManager.h
@@ -35,6 +35,7 @@ extern SaveManager* GBASave;
 QString VerifySetup();
 void Reset();
 bool LoadBIOS();
+void ClearBackupState();
 
 bool LoadROM(QStringList filepath, bool reset);
 void EjectCart();