From 533f0405520fa20289d048a60b23e5f085aca0d9 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Mon, 18 May 2026 11:20:39 +0300 Subject: [PATCH 1/5] Extend tempspace in safe way --- src/jrd/TempSpace.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/jrd/TempSpace.cpp b/src/jrd/TempSpace.cpp index 6e22ecfd869..28b87213d64 100644 --- a/src/jrd/TempSpace.cpp +++ b/src/jrd/TempSpace.cpp @@ -328,9 +328,14 @@ FB_SIZE_T TempSpace::write(offset_t offset, const void* buffer, FB_SIZE_T length void TempSpace::extend(FB_SIZE_T size) { + const auto originalLogicalSize = logicalSize; + const auto originalPhysicalSize = physicalSize; + logicalSize += size; + if (logicalSize <= physicalSize) + return; - if (logicalSize > physicalSize) + try { const FB_SIZE_T initialSize = initialBuffer.getCount(); @@ -399,12 +404,10 @@ void TempSpace::extend(FB_SIZE_T size) } } - // NS 2014-07-31: FIXME: missing exception handling. - // error thrown in block of code below will leave TempSpace in inconsistent state: - // logical/physical size already increased while allocation has in fact failed. if (!block) { // allocate block in the temp file + // Possible error thrown when not enough physical memory TempFile* const file = setupFile(size); fb_assert(file); if (tail && tail->sameFile(file)) @@ -430,6 +433,13 @@ void TempSpace::extend(FB_SIZE_T size) } tail = block; } + catch (...) + { + // Restore original state + logicalSize = originalLogicalSize; + physicalSize = originalPhysicalSize; + throw; + } } // From 54ba0eca1e8b19e5cb125a800a0541e3ba3f16da Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 19 May 2026 08:43:46 +0300 Subject: [PATCH 2/5] Restore `head` and `tail` in `TempSpace::extend` in case of exception --- src/jrd/TempSpace.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/jrd/TempSpace.cpp b/src/jrd/TempSpace.cpp index 28b87213d64..f6a51de3602 100644 --- a/src/jrd/TempSpace.cpp +++ b/src/jrd/TempSpace.cpp @@ -331,6 +331,9 @@ void TempSpace::extend(FB_SIZE_T size) const auto originalLogicalSize = logicalSize; const auto originalPhysicalSize = physicalSize; + AutoPtr delayDelete; // Restore in case of error + Block* originalTail = tail; + logicalSize += size; if (logicalSize <= physicalSize) return; @@ -372,7 +375,7 @@ void TempSpace::extend(FB_SIZE_T size) if (initialSize) { fb_assert(head == tail); - delete head; + delayDelete = head; head = tail = NULL; size = static_cast(FB_ALIGN(logicalSize, minBlockSize)); physicalSize = size; @@ -438,6 +441,8 @@ void TempSpace::extend(FB_SIZE_T size) // Restore original state logicalSize = originalLogicalSize; physicalSize = originalPhysicalSize; + head = delayDelete.release(); + tail = originalTail; throw; } } From a045647e0d206b616b49ee93c268513537a585b1 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 19 May 2026 12:48:56 +0300 Subject: [PATCH 3/5] Better name for original head holder in TempSpace::extend --- src/jrd/TempSpace.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jrd/TempSpace.cpp b/src/jrd/TempSpace.cpp index f6a51de3602..ec0ce2600a7 100644 --- a/src/jrd/TempSpace.cpp +++ b/src/jrd/TempSpace.cpp @@ -331,7 +331,7 @@ void TempSpace::extend(FB_SIZE_T size) const auto originalLogicalSize = logicalSize; const auto originalPhysicalSize = physicalSize; - AutoPtr delayDelete; // Restore in case of error + AutoPtr originalHead; // Delay deletion and restore in case of error Block* originalTail = tail; logicalSize += size; @@ -375,7 +375,7 @@ void TempSpace::extend(FB_SIZE_T size) if (initialSize) { fb_assert(head == tail); - delayDelete = head; + originalHead = head; head = tail = NULL; size = static_cast(FB_ALIGN(logicalSize, minBlockSize)); physicalSize = size; @@ -441,7 +441,7 @@ void TempSpace::extend(FB_SIZE_T size) // Restore original state logicalSize = originalLogicalSize; physicalSize = originalPhysicalSize; - head = delayDelete.release(); + head = originalHead.release(); tail = originalTail; throw; } From 182dfb0b4d3e32b8a10e8d0ee09911e9c314dd7f Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 19 May 2026 17:17:41 +0300 Subject: [PATCH 4/5] Add exception instead of assert for TempSpace::read and TempSpace::write --- src/include/firebird/impl/msg/jrd.h | 1 + src/include/gen/Firebird.pas | 1 + src/jrd/TempSpace.cpp | 12 ++++++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/include/firebird/impl/msg/jrd.h b/src/include/firebird/impl/msg/jrd.h index e3c020d60f9..340fd1fafdb 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -1015,3 +1015,4 @@ FB_IMPL_MSG(JRD, 1012, bad_constant_type, -901, "2F", "000", "@1 is not supporte FB_IMPL_MSG(JRD, 1013, not_defined_constant, -901, "42", "000", "The constant @1 is not defined") FB_IMPL_MSG(JRD, 1014, const_name, -901, "42", "000", "CONSTANT @1") FB_IMPL_MSG(JRD, 1015, private_table, -901, "42", "000", "Table @1 is private to package @2") +FB_IMPL_MSG(JRD, 1016, temp_space_invalid_pos, -901, "HY", "000", "Invalid position to read/write in a temporary file (positon: @1, size: @2)") diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 2b3b1c97065..5303fde2004 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -5972,6 +5972,7 @@ IPerformanceStatsImpl = class(IPerformanceStats) isc_not_defined_constant = 335545333; isc_const_name = 335545334; isc_private_table = 335545335; + isc_temp_space_invalid_pos = 335545336; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; diff --git a/src/jrd/TempSpace.cpp b/src/jrd/TempSpace.cpp index ec0ce2600a7..e44946ee02e 100644 --- a/src/jrd/TempSpace.cpp +++ b/src/jrd/TempSpace.cpp @@ -258,7 +258,11 @@ TempSpace::~TempSpace() FB_SIZE_T TempSpace::read(offset_t offset, void* buffer, FB_SIZE_T length) { - fb_assert(offset + length <= logicalSize); + if (offset + length > logicalSize) + { + status_exception::raise(Arg::Gds(isc_temp_space_invalid_pos) << + Arg::Num(offset + length) << Arg::Num(logicalSize)); + } if (length) { @@ -290,7 +294,11 @@ FB_SIZE_T TempSpace::read(offset_t offset, void* buffer, FB_SIZE_T length) FB_SIZE_T TempSpace::write(offset_t offset, const void* buffer, FB_SIZE_T length) { - fb_assert(offset <= logicalSize); + if (offset > logicalSize) + { + status_exception::raise(Arg::Gds(isc_temp_space_invalid_pos) << + Arg::Num(offset) << Arg::Num(logicalSize)); + } if (offset + length > logicalSize) { From ca7e8262d65055f5bde277f44647fbda8d41389c Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 19 May 2026 18:01:54 +0300 Subject: [PATCH 5/5] Use Arg::Int64 in TempSpace status_vector --- src/jrd/TempSpace.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jrd/TempSpace.cpp b/src/jrd/TempSpace.cpp index e44946ee02e..3f7ec355933 100644 --- a/src/jrd/TempSpace.cpp +++ b/src/jrd/TempSpace.cpp @@ -261,7 +261,7 @@ FB_SIZE_T TempSpace::read(offset_t offset, void* buffer, FB_SIZE_T length) if (offset + length > logicalSize) { status_exception::raise(Arg::Gds(isc_temp_space_invalid_pos) << - Arg::Num(offset + length) << Arg::Num(logicalSize)); + Arg::Int64(offset + length) << Arg::Int64(logicalSize)); } if (length) @@ -297,7 +297,7 @@ FB_SIZE_T TempSpace::write(offset_t offset, const void* buffer, FB_SIZE_T length if (offset > logicalSize) { status_exception::raise(Arg::Gds(isc_temp_space_invalid_pos) << - Arg::Num(offset) << Arg::Num(logicalSize)); + Arg::Int64(offset) << Arg::Int64(logicalSize)); } if (offset + length > logicalSize)