Skip to content

Fix crash from DB locking#1937

Merged
KyleSanderson merged 2 commits intoalliedmodders:masterfrom
sirdigbot:lockdb-fix
Mar 30, 2023
Merged

Fix crash from DB locking#1937
KyleSanderson merged 2 commits intoalliedmodders:masterfrom
sirdigbot:lockdb-fix

Conversation

@sirdigbot
Copy link
Contributor

@sirdigbot sirdigbot commented Feb 19, 2023

Fix for #1936

Not sure if I've gone about this the right way, but it seems to make sense and fixes the crashing with the test code.

public void OnPluginStart()
{
  char sError[512];
  Database db = SQL_Connect("clientprefs", true, sError, sizeof(sError));

  if (db == null)
  {
      SetFailState("Error: %s", sError);
      return;
  }

    
  PrintToServer("ABOUT TO LOCK");

  SQL_LockDatabase(db);
  SQL_LockDatabase(db);
  SQL_UnlockDatabase(db);
  
  PrintToServer("REACHED UNLOCK");
}

image

@dvander
Copy link
Member

dvander commented Feb 20, 2023

This API is horrible in every way, and it'd be much better to close our collective eyes, pretend it doesn't exist, and never use it again.

That said, a cleaner fix would be to switch to std::recursive_mutex and note in the header/include files that Lock/Unlock calls may be nested and must be balanced.

@sirdigbot
Copy link
Contributor Author

Never heard of recursive_mutex until just now, neat.

But is that actually a better solution? The crash is caused when you misuse lock (i.e. extra call or missing unlock), so with recursive_mutex you're trading that UB-potential-crash for a more silent database-deadlock, right? Or am I missing something?
You'd lose track of how many recursions deep you are as opposed to my method which ignores redundant calls--so only a single unlock would be needed to fix the database state.

They both end up doing the same thing but my one is more recoverable from an invalid state, no?

@dvander
Copy link
Member

dvander commented Feb 21, 2023

The API should not be used, at all, ever. The best fix is to remove it.

@dvander
Copy link
Member

dvander commented Feb 21, 2023

And, why: it's fundamentally broken. One, it blocks the main thread, which is a no-no. Two, a native error, spurious or otherwise, could cause the database to become permanently locked. Neither of these are fixable.

So, IMO, deciding on the "right" behavior is moot, when there is a trivial workaround: having two database connections.

@Wend4r
Copy link
Contributor

Wend4r commented Feb 21, 2023

I think a similar thing needs to be done by separate PR/changes for User Messages (I was dealing with Protobuf).

bool g_IsMsgInExec = false;
.
When UM is called inside high UM, the permanently locking to call more because returns many throwing (breaks the SourcePawn backtrace, jumps to the founder invoke (aka forward)).
I have to restart the server (Issue: SM does not safely unload from MM:Source).

@KyleSanderson KyleSanderson merged commit c5087d7 into alliedmodders:master Mar 30, 2023
@sirdigbot sirdigbot deleted the lockdb-fix branch April 10, 2023 03:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants