From 860f17971202432ee7060494a518db48df09bcb4 Mon Sep 17 00:00:00 2001 From: hvlad Date: Sun, 17 Dec 2017 02:05:00 +0200 Subject: [PATCH] Fixed bug CORE-5681 : AV when external statement is executed and local transaction is rolled back --- src/jrd/extds/ExtDS.cpp | 31 +++++++++++++++++++++++++------ src/jrd/extds/ExtDS.h | 4 ++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index 2c3fcb58b4..81ed035e58 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -365,8 +365,24 @@ Transaction* Connection::createTransaction() return tran; } -void Connection::deleteTransaction(Transaction* tran) +void Connection::deleteTransaction(thread_db* tdbb, Transaction* tran) { + // Close all active statements in tran context avoiding commit of already + // deleted transaction + Statement** stmt_ptr = m_statements.begin(); + while (stmt_ptr < m_statements.end()) + { + Statement* stmt = *stmt_ptr; + if (stmt->getTransaction() == tran) + { + if (stmt->isActive()) + stmt->close(tdbb, true); + } + // close() above could destroy statement and remove it from m_statements + if (stmt_ptr < m_statements.end() && *stmt_ptr == stmt) + stmt_ptr++; + } + FB_SIZE_T pos; if (m_transactions.find(tran, pos)) { @@ -378,7 +394,7 @@ void Connection::deleteTransaction(Transaction* tran) } if (!m_used_stmts && m_transactions.getCount() == 0 && !m_deleting) - m_provider.releaseConnection(JRD_get_thread_data(), *this); + m_provider.releaseConnection(tdbb, *this); } Statement* Connection::createStatement(const string& sql) @@ -657,7 +673,7 @@ void Transaction::commit(thread_db* tdbb, bool retain) if (!retain) { detachFromJrdTran(); - m_connection.deleteTransaction(this); + m_connection.deleteTransaction(tdbb, this); } } @@ -670,7 +686,7 @@ void Transaction::rollback(thread_db* tdbb, bool retain) if (!retain) { detachFromJrdTran(); - m_connection.deleteTransaction(this); + m_connection.deleteTransaction(tdbb, this); } if (status->getState() & IStatus::STATE_ERRORS) { @@ -710,7 +726,7 @@ Transaction* Transaction::getTransaction(thread_db* tdbb, Connection* conn, TraS } catch (const Exception&) { - conn->deleteTransaction(ext_tran); + conn->deleteTransaction(tdbb, ext_tran); throw; } } @@ -913,7 +929,7 @@ bool Statement::fetch(thread_db* tdbb, const ValueListNode* out_params) return true; } -void Statement::close(thread_db* tdbb) +void Statement::close(thread_db* tdbb, bool invalidTran) { // we must stuff exception if and only if this is the first time it occurs // once we stuff exception we must punt @@ -942,6 +958,9 @@ void Statement::close(thread_db* tdbb) unBindFromRequest(); } + if (invalidTran) + m_transaction = NULL; + if (m_transaction && m_transaction->getScope() == traAutonomous) { bool commitFailed = false; diff --git a/src/jrd/extds/ExtDS.h b/src/jrd/extds/ExtDS.h index 7b3c7f30d9..62e2db3946 100644 --- a/src/jrd/extds/ExtDS.h +++ b/src/jrd/extds/ExtDS.h @@ -201,7 +201,7 @@ public: // transaction into m_transactions array and delete not needed transaction // immediately (as we didn't pool transactions) Transaction* createTransaction(); - void deleteTransaction(Transaction* tran); + void deleteTransaction(Jrd::thread_db* tdbb, Transaction* tran); // Statements management within connection scope : put newly created // statement into m_statements array, but don't delete freed statement @@ -325,7 +325,7 @@ public: void open(Jrd::thread_db* tdbb, Transaction* tran, const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params, bool singleton); bool fetch(Jrd::thread_db* tdbb, const Jrd::ValueListNode* out_params); - void close(Jrd::thread_db* tdbb); + void close(Jrd::thread_db* tdbb, bool invalidTran = false); void deallocate(Jrd::thread_db* tdbb); const Firebird::string& getSql() const { return m_sql; }