From 8597483ba66613abe6a2acbc689e614b31efc87d Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Mon, 15 Dec 2025 16:08:44 +0200 Subject: [PATCH 1/2] Fixed potential endless loop inside MET_scan_relation: when relation is system-defined and its ODS is greater than ODS of current database. Thanks to @dyemanov for pointing into this. --- src/jrd/met.epp | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/jrd/met.epp b/src/jrd/met.epp index ebefdc777ef..92b2c0e811d 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -115,6 +115,7 @@ static int blocking_ast_relation(void*); static int partners_ast_relation(void*); static int rescan_ast_relation(void*); static ULONG get_rel_flags_from_FLAGS(USHORT); +static USHORT get_sysrel_ods(jrd_rel*); static void get_trigger(thread_db*, jrd_rel*, bid*, bid*, TrigVector**, const TEXT*, FB_UINT64, SSHORT, USHORT, const MetaName&, const string&, const bid*, Nullable ssDefiner); static bool get_type(thread_db*, USHORT*, const UCHAR*, const TEXT*); @@ -4095,9 +4096,13 @@ static void scan_relation(thread_db* tdbb, jrd_rel* relation) AutoCacheRequest request(tdbb, irq_r_fields, IRQ_REQUESTS); CompilerScratch* csb = NULL; + bool found = false; + FOR(REQUEST_HANDLE request) REL IN RDB$RELATIONS WITH REL.RDB$RELATION_ID EQ relation->rel_id { + found = true; + // Pick up relation level stuff relation->rel_current_fmt = REL.RDB$FORMAT; vec* vector = relation->rel_fields = @@ -4371,6 +4376,30 @@ static void scan_relation(thread_db* tdbb, jrd_rel* relation) delete csb; + if (!found && !(relation->rel_flags & REL_scanned)) + { + // Relation was not found in RDB$RELATIONS. It could be system relation + // defined in INI for latest supported ODS while database is in older ODS. + + const USHORT dbbOds = ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_version); + + if (relation->isSystem() && dbbOds < ODS_CURRENT_VERSION && + dbbOds < get_sysrel_ods(relation)) + { + relation->rel_flags |= REL_scanned; + } + else + { + fb_assert(false); + + string name(relation->rel_name); + if (name.isEmpty()) + name.printf("", relation->rel_id); + + ERR_post(Arg::Gds(isc_relnotdef) << Arg::Str(name)); + } + } + // We have just loaded the triggers onto the local vector triggers. // It's now time to place them at their rightful place inside the relation block. @@ -4776,6 +4805,37 @@ ULONG MET_get_rel_flags_from_TYPE(USHORT type) } +// Search system-defined list for given relation and return its ODS. +// Return zero, if not found. +static USHORT get_sysrel_ods(jrd_rel* relation) +{ + if (relation->rel_id >= rel_MAX) + return 0; + +#define RELATION(name, id, ods, type) id, ods, +#define FIELD(symbol, name, id, update, ods) +#define END_RELATION + + static const int rels[] = + { + #include "../jrd/relations.h" + 0, 0 + }; + +#undef RELATION +#undef FIELD +#undef END_RELATION + + for (int n = 0; n < FB_NELEM(rels); n += 2) + { + if (relation->rel_id == rels[n]) + return rels[n + 1]; + } + + return 0; +} + + static void get_trigger(thread_db* tdbb, jrd_rel* relation, bid* blob_id, bid* debug_blob_id, TrigVector** ptr, const TEXT* name, FB_UINT64 type, From 9ca15bea6a0bf23a2d07372f27bbe34c62042ef7 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Mon, 15 Dec 2025 18:05:43 +0200 Subject: [PATCH 2/2] Relaxed check as @dyemanov suggested --- src/jrd/met.epp | 41 +++-------------------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 92b2c0e811d..53cb28213c4 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -115,7 +115,6 @@ static int blocking_ast_relation(void*); static int partners_ast_relation(void*); static int rescan_ast_relation(void*); static ULONG get_rel_flags_from_FLAGS(USHORT); -static USHORT get_sysrel_ods(jrd_rel*); static void get_trigger(thread_db*, jrd_rel*, bid*, bid*, TrigVector**, const TEXT*, FB_UINT64, SSHORT, USHORT, const MetaName&, const string&, const bid*, Nullable ssDefiner); static bool get_type(thread_db*, USHORT*, const UCHAR*, const TEXT*); @@ -4378,13 +4377,10 @@ static void scan_relation(thread_db* tdbb, jrd_rel* relation) if (!found && !(relation->rel_flags & REL_scanned)) { - // Relation was not found in RDB$RELATIONS. It could be system relation - // defined in INI for latest supported ODS while database is in older ODS. + // Relation was not found in RDB$RELATIONS. It could be system virtual relation + // defined in INI. - const USHORT dbbOds = ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_version); - - if (relation->isSystem() && dbbOds < ODS_CURRENT_VERSION && - dbbOds < get_sysrel_ods(relation)) + if (relation->isSystem() && relation->isVirtual()) { relation->rel_flags |= REL_scanned; } @@ -4805,37 +4801,6 @@ ULONG MET_get_rel_flags_from_TYPE(USHORT type) } -// Search system-defined list for given relation and return its ODS. -// Return zero, if not found. -static USHORT get_sysrel_ods(jrd_rel* relation) -{ - if (relation->rel_id >= rel_MAX) - return 0; - -#define RELATION(name, id, ods, type) id, ods, -#define FIELD(symbol, name, id, update, ods) -#define END_RELATION - - static const int rels[] = - { - #include "../jrd/relations.h" - 0, 0 - }; - -#undef RELATION -#undef FIELD -#undef END_RELATION - - for (int n = 0; n < FB_NELEM(rels); n += 2) - { - if (relation->rel_id == rels[n]) - return rels[n + 1]; - } - - return 0; -} - - static void get_trigger(thread_db* tdbb, jrd_rel* relation, bid* blob_id, bid* debug_blob_id, TrigVector** ptr, const TEXT* name, FB_UINT64 type,