Re: Should /usr/include/fts.h adding fts_dirfd and __fts_reserved[3] to FTSENT (a.k.a. struct _ftsent) require a change from libc.so.7 to .8 because of some resulting binary incompatibilities?

From: Mark Millard <marklmi_at_yahoo.com>
Date: Sun, 27 Sep 2026 20:19:15 UTC
On 9/24/26 20:06, Konstantin Belousov wrote:
> On Thu, Sep 24, 2026 at 06:57:04PM -0700, Mark Millard wrote:
>> On 9/24/26 17:16, Mark Millard wrote:
>>> On 9/24/26 16:40, Warner Losh wrote:
>>>> No. Symbol versioning.
>>>
>>> jevents has no symbol versioning for its own, internal implementation of
>>> a function it decided to name fts_compare as far as I can tell. That
>>> same fts_compare implementation is passed in everywhere that the same
>>> libc.so.7 naming is in use and then is called no matter what,
>>> independent of which fts.h vintage it was built with.
>>>
>>> If symbol versioning applies here, how does it work?
>>>
>>> (Why I ended up with the mix of an older jevents with a post-change
>>> environment is a separate issue and is my fault. But nothing rejected or
>>> fixed the combination. libc.so.8 vs. libc.so.7 would have rejected.)
>>
>> Your note caused me to somewhat better isolate the structure of the mix:
>>
>> The kernel is updated  to  : 1600026
>> The world  is updating from: 1600019 (so: old fts.h)
>> The world  is updating to  : 1600026 (or trying to)
>>
>> # readelf -a
>> /usr/obj/BUILDs/main-CA76-dbg-clang/usr/main-src/arm64.aarch64/lib/libc/libc.so.7
>> | grep fts_open@
>> 0000000000243d10  00000c7a00000402 R_AARCH64_JUMP_SLOT
>> 00000000000c0c40 fts_open@@FBSD_1.9 + 0
>>   3194: 00000000000c0c40   128 FUNC    GLOBAL DEFAULT    14
>> fts_open@@FBSD_1.9
>>   3195: 00000000000c29c0  1016 FUNC    GLOBAL DEFAULT    14
>> fts_open@FBSD_1.0
>>   3196: 00000000000c4260   924 FUNC    GLOBAL DEFAULT    14
>> fts_open@FBSD_1.1
>>   3197: 00000000000c5b60   124 FUNC    GLOBAL DEFAULT    14
>> fts_open@FBSD_1.5
>>
>> (Associated with building from modern 1600026 source at the time.)
>>
>> jevents got:
>>
>> # readelf -a
>> /usr/obj/BUILDs/main-CA76-dbg-clang/usr/main-src/arm64.aarch64/lib/libpmc/pmu-events/jevents
>> | grep fts_open@
>> 0000000000037680  0000001300000402 R_AARCH64_JUMP_SLOT
>> 0000000000000000 fts_open@FBSD_1.9 + 0
>>     19: 0000000000000000     0 FUNC    GLOBAL DEFAULT   UND
>> fts_open@FBSD_1.9
>>
>>
>> But, as a build-tool, jevents was built with /usr/include/fts.h instead
>> of with the /usr/main-src/ tree that I use for the build if the update.
>> (/usr/src/ is from pkgbase.):
>>
>> # diff -u /usr/include/fts.h /usr/main-src/include/fts.h
>> --- /usr/include/fts.h	2025-05-11 07:29:42.791259000 -0700
>> +++ /usr/main-src/include/fts.h	2026-09-18 16:13:35.766402000 -0700
>> @@ -1,4 +1,4 @@
>> -/*-
>> +/*
>>   * SPDX-License-Identifier: BSD-3-Clause
>>   *
>>   * Copyright (c) 1989, 1993
>> @@ -92,6 +92,8 @@
>>  	char *fts_path;			/* root path */
>>  	int fts_errno;			/* errno for this node */
>>  	int fts_symfd;			/* fd for symlink */
>> +	int fts_dirfd;                  /* fd for this directory, if a
>> directory */
>> +	int __fts_reserved[3];          /* reserved for future use */
>>  	__size_t fts_pathlen;		/* strlen(fts_path) */
>>  	__size_t fts_namelen;		/* strlen(fts_name) */
>>
>> @@ -146,6 +148,8 @@
>>  #define	 fts_get_stream(ftsent)	((ftsent)->fts_fts)
>>  FTS	*fts_open(char * const *, int,
>>  	    int (*)(const FTSENT * const *, const FTSENT * const *));
>> +FTS	*fts_openat(int, char * const *, int,
>> +	    int (*)(const FTSENT * const *, const FTSENT * const *));
>>  #ifdef __BLOCKS__
>>  FTS	*fts_open_b(char * const *, int,
>>  	    int (^)(const FTSENT * const *, const FTSENT * const *));
>>
>> Thus the result was a jevents using:
>>
>> ) the old /usr/include/fts.h header of its "host" environment
>> but also:
>> ) the new symbol version fts_open@@FBSD_1.9 was used.
>>
>> Nothing rejected the bad combination (other than a later SIGSEGV).
> 
> Right, if it is the case, then the ABI mismatch is unavoidable.
> By itself, this sounds like a serious bug in our build system.
> 
>>
>> I do not see how /usr/include/fts.h file content would end up somehow in
>> control over fts_open@@FBSD_1.5 vs. fts_open@@FBSD_1.9 being used for
>> the likes of the jevents build.
> 
> Include files provide a part of the ABI, which is used by compiler.
> In particular, include files define the layout of C structures.
> 
> Shared libraries provide another part, giving the (default) versions to the
> symbols referenced by the final object.  Layout of the parameters to
> the specific version of the function must match to what headers used
> at compile time defined.
> 
> Mixing these parts across ABI changes cannot work.
> 
> 

I think I've identified what went wrong in the history of trying this
update in my context: a separate installworld race issue (-j used) lead
to an initial partial update of the chroot/jail tree, where:

) libc.so.7 updated before that installworld failed.

) /usr/include/fts.h did not.
  (Would have installed after the installworld failure point.)

So later activity then had the incoherent mix without me identifying it
at the time. For this sequencing, libc.so.8 use would not have helped.

(Via avoiding -j use for installworld I've gotten all my chroot/jail
tree personal builds to avoid the race.)

-- 
===
Mark Millard
marklmi at yahoo.com