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
Attachments:
0001-make-SysCacheIdentifier-be-part-of-ABI.patchtext/x-diff; charset=us-ascii; name=0001-make-SysCacheIdentifier-be-part-of-ABI.patchDownload+10-0
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
Attachments:
v1-0001-Use-SysCacheIdentifier-enum-instead-of-int.patchtext/x-patch; charset=UTF-8; name=v1-0001-Use-SysCacheIdentifier-enum-instead-of-int.patchDownload+34-35
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
Attachments:
v2-0001-Use-SysCacheIdentifier-enum-instead-of-int.patchtext/x-patch; charset=UTF-8; name=v2-0001-Use-SysCacheIdentifier-enum-instead-of-int.patchDownload+98-97
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
Attachments:
v3-0001-Use-SysCacheIdentifier-enum-instead-of-int.patchtext/plain; charset=us-asciiDownload+140-131
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:223The 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.cThe 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 prefersSplitting 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