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?
- Reply: Konstantin Belousov : "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?"
- In reply to: Mark Millard : "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?"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 25 Sep 2026 01:57:04 UTC
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).
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.
Mark
>
>>
>> Warner
>>
>> On Thu, Sep 24, 2026, 5:37 PM Mark Millard <marklmi@yahoo.com
>> <mailto:marklmi@yahoo.com>> wrote:
>>
>> The SHLIB_MAJOR last changed on 2006-05-21 and is:
>>
>> LIB=c
>> SHLIB_MAJOR= 7
>>
>> Changes to the binary interface for function (pointers) passed into any
>> FreeBSD libc inteferface functions lead to incompatibilities. In this
>> case FTSENT (a.k.a. struct _ftsent) is used via function arguments in:
>>
>> 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 *));
>>
>> but, as of 2026-08-03, the content of the *FTSENT (i.e.,
>> struct _ftsent) was updated in a non-binary compatible way:
>>
>> author Jitendra Bhati <bhatijitendra2022@gmail.com
>> <mailto:bhatijitendra2022@gmail.com>> 2026-06-12 17:07:55
>> +0000
>> committer Alan Somers <asomers@FreeBSD.org> 2026-08-03
>> 19:12:28 +0000
>> commit 4bd01d6ae01632501b63438b8d9a401db9744a78 (patch)
>> tree e896c1844fa0fa5897efc4e591ebe02f59a64e61 /include/fts.h
>> parent 9590878fca68e62c63d607da73139698e204d0f0 (diff)
>>
>> . . .
>>
>> Sponsored by: Google LLC (GSoC 2026)
>> Reviewed by: asomers
>> Pull Request: https://github.com/freebsd/freebsd-src/pull/2303
>> <https://github.com/freebsd/freebsd-src/pull/2303>
>> Diffstat (limited to 'include/fts.h')
>> -rw-r--r-- include/fts.h 2
>> 1 files changed, 2 insertions, 0 deletions
>> diff --git a/include/fts.h b/include/fts.h
>> index 479905bda463..0308b8ff880b 100644
>> --- a/include/fts.h
>> +++ b/include/fts.h
>> @@ -92,6 +92,8 @@ struct _ftsent {
>> char *fts_path; /* root path */
>> int fts_errno; /* errno for this node */
>> int fts_symfd; /* fd for symlink */
>> + int fts_dirfd; /* fd for parent directory */
>> + int __fts_reserved[3]; /* reserved for future use */
>> __size_t fts_pathlen; /* strlen(fts_path) */
>> __size_t fts_namelen; /* strlen(fts_name) */
>>
>> There is a lot more after what is visible in the diff (starting with the
>> inserted fields to have it all together):
>>
>> 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) */
>>
>> __ino_t fts_ino; /* inode */
>> __dev_t fts_dev; /* device */
>> __nlink_t fts_nlink; /* link count */
>>
>> #define FTS_ROOTPARENTLEVEL -1
>> #define FTS_ROOTLEVEL 0
>> long fts_level; /* depth (-1 to N) */
>>
>> #define FTS_D 1 /* preorder directory */
>> . . .
>> #define FTS_W 14 /* whiteout object */
>> int fts_info; /* user status for FTSENT
>> structure */
>>
>> #define FTS_DONTCHDIR 0x01 /* don't chdir .. to the
>> parent */
>> #define FTS_SYMFOLLOW 0x02 /* followed a symlink to get
>> here */
>> #define FTS_ISW 0x04 /* this is a whiteout object */
>> unsigned fts_flags; /* private flags for FTSENT
>> structure */
>>
>> #define FTS_AGAIN 1 /* read node again */
>> ...
>> #define FTS_SKIP 4 /* discard node */
>> int fts_instr; /* fts_set() instructions */
>>
>> struct stat *fts_statp; /* stat(2) information */
>> char *fts_name; /* file name */
>> FTS *fts_fts; /* back pointer to main FTS */
>> };
>>
>>
>> An example is in src/tree/lib/libpmc/pmu-events/jevents.c that has:
>>
>> #include <fts.h>
>>
>> static int
>> #if defined(__linux__) || defined(__APPLE__)
>> fts_compare(const FTSENT **a, const FTSENT **b)
>> #else
>> fts_compare(const FTSENT * const *a, const FTSENT * const *b)
>> #endif
>> {
>> return (strcmp((*a)->fts_name, (*b)->fts_name));
>> }
>>
>> Note that the compile time offset for ->fts_name change changes
>> depending on which header version was used and that it will not track
>> the environment that jevents is run in.
>>
>> The same jevent executable file's fts_compare code (non-linux/non-apple)
>> is compatible with only one of:
>>
>> ) a libc.so.7 *FTSENT from before the 2026-08-03 change
>> vs.
>> ) a libc.so.7 *FTSENT from after the 2026-08-03 change
>>
>>
>> I have observed SIGSEGV with backtraces that show the failure at such a
>> fts_compare (*?)->fts_name based deference. That is what eventually
>> resulted in my noticing the above in this unfamiliar code.
>>
>>
>> --
>> ===
>> Mark Millard
>> marklmi at yahoo.com <http://yahoo.com>
>>
>>
>
>
--
===
Mark Millard
marklmi at yahoo.com