Description
Session tables are handed out from a pool and go back to it when the code that took one is done with it. Working with a table after that — or with one that belongs to somebody else — is checked, but the check only writes a line into the assert log and the statement runs anyway.
What runs is silent damage. A change of a table that is already free fills it for whoever gets it next, so that code reads its own rows plus somebody else's. A change of another owner's live table corrupts data the other side is still using. In both cases nothing fails, nothing is retried, and the result surfaces later as wrong data with no connection to the place that caused it.
The same holds for reading a table whose owner is gone: the query returns rows that may already belong to a new owner.
There is no way for an application to run into this by itself — a stale reference is kept inside the platform. But when it happens, the application is the one that gets the wrong numbers.
Reason
An error at the moment of the violation names the operation and the owner that broke the rule; the current log line is written long before anyone notices the data is wrong, and by then the table has usually been handed on again.
Two things have to be done in order, and the first is what makes this more than a two-line change:
- the registry of issued tables can currently be read only under the lock that serializes issuing and returning ("все использования assertLock"). The check runs from places where that lock cannot be taken — a change made from an
INTERNAL DB callback already holds the connection lock, and taking the table lock on top of it is exactly the order that deadlocks against a table being returned in parallel. So the registry has to become safe to read without that lock first;
- only then can the check refuse the operation instead of logging it. The read check has to stay a log even then: a query legitimately joins tables of several owners, and it runs from a point where the connection lock is already held.
A setting should restore the previous behavior for an installation that hits this on an upgrade.
Description
Session tables are handed out from a pool and go back to it when the code that took one is done with it. Working with a table after that — or with one that belongs to somebody else — is checked, but the check only writes a line into the assert log and the statement runs anyway.
What runs is silent damage. A change of a table that is already free fills it for whoever gets it next, so that code reads its own rows plus somebody else's. A change of another owner's live table corrupts data the other side is still using. In both cases nothing fails, nothing is retried, and the result surfaces later as wrong data with no connection to the place that caused it.
The same holds for reading a table whose owner is gone: the query returns rows that may already belong to a new owner.
There is no way for an application to run into this by itself — a stale reference is kept inside the platform. But when it happens, the application is the one that gets the wrong numbers.
Reason
An error at the moment of the violation names the operation and the owner that broke the rule; the current log line is written long before anyone notices the data is wrong, and by then the table has usually been handed on again.
Two things have to be done in order, and the first is what makes this more than a two-line change:
INTERNAL DBcallback already holds the connection lock, and taking the table lock on top of it is exactly the order that deadlocks against a table being returned in parallel. So the registry has to become safe to read without that lock first;A setting should restore the previous behavior for an installation that hits this on an upgrade.