Обсуждение: Our ABI diff infrastructure ignores enum SysCacheIdentifier
I discovered $SUBJECT while working on commits dbb09fd8e et al.
The point of those commits was to back-patch addition of a syscache
that previously existed only in v18+, so naturally I was concerned
about not breaking ABI by changing any existing syscache's ID.
I tested whether abidiff would bleat about it if I intentionally
changed an ID, and found that *it didn't*.
I don't think this is (quite) a bug in libabigail. They are pretty
clear that what they regard as ABI is:
... the descriptions of the types reachable by the interfaces
(functions and variables) that are visible outside of their
translation unit.
We do not use enum SysCacheIdentifier as the declared type of any
global variable or any globally-visible function argument or result.
Therefore it's not ABI per their definition.
This is frankly pretty scary. Now that we know the rules, we can
fix it for enum SysCacheIdentifier, but we have other things that are
similarly vulnerable. The thing I am most concerned about right now
is enum GUCs. The guc.c APIs mandate that those be declared as type
int, so I think (haven't actually checked) that most if not all of
the associated enum values will not be perceived as ABI-relevant by
abidiff. What can we do about that?
As for SysCacheIdentifier, the root of the problem is that
SearchSysCache and friends are declared to take "int cacheId"
not "enum SysCacheIdentifier cacheId". Likely we should change
that in HEAD, but that'd be an actual not theoretical ABI break
(the enum's not necessarily int-width). In the back branches
I'm thinking about adding a dummy function just for this purpose,
more or less as in the under-commented patch attached.
Thoughts?
regards, tom lane
commit 12d2a8cd596d63dd908149b9140f527b723585cc
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat Jan 10 18:28:39 2026 -0500
Make SysCacheIdentifier be ABI.
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index f7f4f56a4d2..1af3ab3afdf 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -671,6 +671,14 @@ GetSysCacheHashValue(int cacheId,
return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
}
+/*
+ * Dummy function with an "enum SysCacheIdentifier" parameter.
+ */
+void
+SysCacheDummy(enum SysCacheIdentifier cacheId)
+{
+}
+
/*
* List-search interface
*/
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index b541911c8fc..052c4550d22 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -72,6 +72,8 @@ extern Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup,
extern uint32 GetSysCacheHashValue(int cacheId,
Datum key1, Datum key2, Datum key3, Datum key4);
+extern void SysCacheDummy(enum SysCacheIdentifier cacheId);
+
/* list-search interface. Users of this must import catcache.h too */
struct catclist;
extern struct catclist *SearchSysCacheList(int cacheId, int nkeys,
On Thu, Feb 12, 2026 at 11:17:37AM -0500, Tom Lane wrote: > I discovered $SUBJECT while working on commits dbb09fd8e et al. > The point of those commits was to back-patch addition of a syscache > that previously existed only in v18+, so naturally I was concerned > about not breaking ABI by changing any existing syscache's ID. > I tested whether abidiff would bleat about it if I intentionally > changed an ID, and found that *it didn't*. Well. That's annoying. This one is important to be careful about. > As for SysCacheIdentifier, the root of the problem is that > SearchSysCache and friends are declared to take "int cacheId" > not "enum SysCacheIdentifier cacheId". Likely we should change > that in HEAD, but that'd be an actual not theoretical ABI break > (the enum's not necessarily int-width). Enforcing a type for this sounds like a good idea in the long term on HEAD, yes, even putting the ABI argument aside for a moment. I'd suggest the addition of an extra typedef in the code generated for syscache_ids.h to save from a couple of enum markers in these declarations, once refactored to use the new enum type. > In the back branches > I'm thinking about adding a dummy function just for this purpose, > more or less as in the under-commented patch attached. > > Thoughts? Adding a comment explaining why this function needs to exist would be good. -- Michael
Вложения
On 2/12/26 5:17 PM, Tom Lane wrote: > As for SysCacheIdentifier, the root of the problem is that > SearchSysCache and friends are declared to take "int cacheId" > not "enum SysCacheIdentifier cacheId". Likely we should change > that in HEAD, but that'd be an actual not theoretical ABI break > (the enum's not necessarily int-width). In the back branches > I'm thinking about adding a dummy function just for this purpose, > more or less as in the under-commented patch attached. > > Thoughts? Attached a patch which changes that in HEAD and I think for HEAD the best solution is the just fix all cases where we use ints like this to actually use the enum. As for back branches I agree with Michael, just add a comment explaining why this dummy function is necessary. Andreas
Вложения
On Fri, Feb 13, 2026 at 06:46:55AM +0100, Andreas Karlsson wrote: > Attached a patch which changes that in HEAD and I think for HEAD the best > solution is the just fix all cases where we use ints like this to actually > use the enum. I was expecting something a bit more complicated. Nice at quick glance, Andreas. -- Michael
Вложения
On 2/13/26 9:24 AM, Michael Paquier wrote: > I was expecting something a bit more complicated. Nice at quick > glance, Andreas. It is a bit more code churn if I also include inval.c, but I still do not think it would be too bad. Andreas
Вложения
While it isn't strictly ABI, this made me wonder about the static inline functions in public headers. Wouldn't extensions using those, compiled with older minor versions have similar issues as issues caused by actual ABI incompatibility? I did a quick test with scripts about this in the REL 17 branch, and there are several changes that could cause issues in theory. See ffd9b8134658 for example introduced in 17.3. While technically this is ABI compatible (nbanks is the same size as bank_mask in the public struct, no binary change), part of the modified calculation is in an inline function in the header, but part of it is in the C part. Extensions compiled against 17.2 or earlier and using this functionality will misbehave in 17.3 or later, as only part of the code gets updated. Similar issues could be caused by macro changes, for example COPYCHAR was changed from memcpy to ts_copychar_cstr. That doesn't seem to be an actual issue, but it could have been with a different change, and I think similarly could go unnoticed. There are also cases where something was simply removed from public headers (firstbyte64(v) define from hashfn_unstable.h for example). This again wouldn't cause any issues as long as the functions called by it are still there, but it seems to break source compatibility between minor versions.
On Fri, Feb 13, 2026 at 10:36:41AM +0100, Andreas Karlsson wrote: > It is a bit more code churn if I also include inval.c, but I still do not > think it would be too bad. The blast looks acceptable with inval.c in sight. What's less acceptable is the set of failures generated, like: #3 0x00000000019e7ac4 in ExceptionalCondition (conditionName=0x1e31ff0 "cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]", fileName=0x1e31e80 "syscache.c", lineNumber=223) at assert.c:65 #4 0x00000000019d277e in SearchSysCache1 (cacheId=4294967295, key1=16778) at syscache.c:223 I didn't look beyond that. -- Michael
Вложения
On Mon, Feb 16, 2026 at 04:47:24PM +0900, Michael Paquier wrote: > The blast looks acceptable with inval.c in sight. What's less > acceptable is the set of failures generated, like: > #3 0x00000000019e7ac4 in ExceptionalCondition > (conditionName=0x1e31ff0 "cacheId >= 0 && cacheId < SysCacheSize && > SysCache[cacheId]", fileName=0x1e31e80 "syscache.c", > lineNumber=223) at assert.c:65 > #4 0x00000000019d277e in SearchSysCache1 (cacheId=4294967295, > key1=16778) at syscache.c:223 The issue here is that we have three code paths that are perfectly OK with dealing in negative syscache ID values: - DropObjectById()@dependency.c - AlterObjectRename_internal()@alter.c - AlterObjectNamespace_internal()@alter.c The best path moving forward on this one that I can think of in objectaddress.c would be to add an extra "invalid" value in the enum of SysCacheIdentifier and attach that to the ObjectProperty that we can use to mark when we don't have an ID assigned. That would have the advantage to self-document the behavior that we don't have a syscache entry at all when using this invalid ID. What do you think about the updated version attached? -- Michael
Вложения
On 2/17/26 7:58 AM, Michael Paquier wrote: > On Mon, Feb 16, 2026 at 04:47:24PM +0900, Michael Paquier wrote: >> The blast looks acceptable with inval.c in sight. What's less >> acceptable is the set of failures generated, like: >> #3 0x00000000019e7ac4 in ExceptionalCondition >> (conditionName=0x1e31ff0 "cacheId >= 0 && cacheId < SysCacheSize && >> SysCache[cacheId]", fileName=0x1e31e80 "syscache.c", >> lineNumber=223) at assert.c:65 >> #4 0x00000000019d277e in SearchSysCache1 (cacheId=4294967295, >> key1=16778) at syscache.c:223 > > The issue here is that we have three code paths that are perfectly OK > with dealing in negative syscache ID values: > - DropObjectById()@dependency.c > - AlterObjectRename_internal()@alter.c > - AlterObjectNamespace_internal()@alter.c > > The best path moving forward on this one that I can think of in > objectaddress.c would be to add an extra "invalid" value in the enum > of SysCacheIdentifier and attach that to the ObjectProperty that we > can use to mark when we don't have an ID assigned. That would have > the advantage to self-document the behavior that we don't have a > syscache entry at all when using this invalid ID. > > What do you think about the updated version attached? Yeah, that looks like a quite nice improvement. My only comment is that if it was me I would have split it into two patches, one introducing the invalid and one replacing int. But you are much more familiar than me with what granularity of commits the project prefers Andreas
On Tue, Feb 17, 2026 at 09:20:44AM +0100, Andreas Karlsson wrote: > Yeah, that looks like a quite nice improvement. My only comment is that if > it was me I would have split it into two patches, one introducing the > invalid and one replacing int. But you are much more familiar than me with > what granularity of commits the project prefers Splitting that into two is probably better, yes. Even if both changes touch the same portions of perl script, it makes the introduction of the two concepts cleaner. -- Michael
Вложения
On Tue, Feb 17, 2026 at 05:59:31PM +0900, Michael Paquier wrote: > On Tue, Feb 17, 2026 at 09:20:44AM +0100, Andreas Karlsson wrote: >> Yeah, that looks like a quite nice improvement. My only comment is that if >> it was me I would have split it into two patches, one introducing the >> invalid and one replacing int. But you are much more familiar than me with >> what granularity of commits the project prefers > > Splitting that into two is probably better, yes. Even if both changes > touch the same portions of perl script, it makes the introduction of > the two concepts cleaner. The conclusion of this exercise is that I have spotted two more spots that checked for an invalid syscache ID based on a hardcoded value of -1, and I have replaced them with the new value assigned in the enum. A few more of these checked for a positive value. There was also one spot that I've found was incorrect, fixed separately as of f7df12a66cc9. The buildfarm is not complaining after c06b5b99bbb0 and ee642cccc43c, meaning that we are hopefully good for v19 and future versions. -- Michael