Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 941890 - net-analyzer/wireshark: fails tests with LTO
Summary: net-analyzer/wireshark: fails tests with LTO
Status: RESOLVED FIXED
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: Current packages (show other bugs)
Hardware: All Linux
: Normal normal
Assignee: Holger Hoffstätte
URL:
Whiteboard:
Keywords: PullRequest, TESTFAILURE
Depends on:
Blocks: lto
  Show dependency tree
 
Reported: 2024-10-20 14:09 UTC by Sam James
Modified: 2025-05-01 00:44 UTC (History)
3 users (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-10-20 14:09:33 UTC
See https://gitlab.com/wireshark/wireshark/-/issues/18216. Upstream have worked around it recently by adding -fno-delete-null-pointer-checks.

--

$ gdb --args /home/sam/git/wireshark/build/run/wmem_test -r /wmem/datastruct/tree
Reading symbols from /home/sam/git/wireshark/build/run/wmem_test...
(gdb) r
Starting program: /home/sam/git/wireshark/build/run/wmem_test -r /wmem/datastruct/tree
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib64/libthread_db.so.1".
TAP version 13
# random seed: R02Se575e43e0b730f62f2f3ae6f6e419470
# Start of wmem tests
# Start of datastruct tests
=================================================================
==1433924==ERROR: AddressSanitizer: heap-use-after-free on address 0x5080002b11c8 at pc 0x555555556e38 bp 0x7fffffffd090 sp 0x7fffffffd080
READ of size 8 at 0x5080002b11c8 thread T0
    #0 0x555555556e37 in wmem_tree_foreach_nodes /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:755
    #1 0x555555573e34 in wmem_tree_foreach /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:789
    #2 0x555555573e34 in wmem_tree_count /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:316
    #3 0x555555573e34 in wmem_test_tree /home/sam/git/wireshark/wsutil/wmem/wmem_test.c:1238
    #4 0x7ffff772075b in test_case_run ../glib-2.78.6/glib/gtestutils.c:3161
    #5 0x7ffff772075b in g_test_run_suite_internal ../glib-2.78.6/glib/gtestutils.c:3256
    #6 0x7ffff77204ba in g_test_run_suite_internal ../glib-2.78.6/glib/gtestutils.c:3273
    #7 0x7ffff77204ba in g_test_run_suite_internal ../glib-2.78.6/glib/gtestutils.c:3273
    #8 0x7ffff7720f4a in g_test_run_suite ../glib-2.78.6/glib/gtestutils.c:3352
    #9 0x7ffff772102b in g_test_run ../glib-2.78.6/glib/gtestutils.c:2462
    #10 0x7ffff772102b in g_test_run ../glib-2.78.6/glib/gtestutils.c:2449
    #11 0x5555555549d1 in main /home/sam/git/wireshark/wsutil/wmem/wmem_test.c:1478
    #12 0x7ffff73db746 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #13 0x7ffff73db7f6 in __libc_start_main_impl ../csu/libc-start.c:360
    #14 0x555555554ae0 in _start (/home/sam/git/wireshark/build/run/wmem_test+0xae0)

0x5080002b11c8 is located 40 bytes inside of 88-byte region [0x5080002b11a0,0x5080002b11f8)
freed by thread T0 here:
    #0 0x7ffff79234db in free /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/asan/asan_malloc_linux.cpp:52
    #1 0x55555555b44b in wmem_strict_free_all /home/sam/git/wireshark/wsutil/wmem/wmem_allocator_strict.c:182

previously allocated by thread T0 here:
    #0 0x7ffff792482b in malloc /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7ffff76ee1ad in g_malloc ../glib-2.78.6/glib/gmem.c:130

SUMMARY: AddressSanitizer: heap-use-after-free /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:755 in wmem_tree_foreach_nodes
Shadow bytes around the buggy address:
  0x5080002b0f00: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b0f80: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b1000: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b1080: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b1100: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
=>0x5080002b1180: fa fa fa fa fd fd fd fd fd[fd]fd fd fd fd fd fa
  0x5080002b1200: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b1280: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b1300: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b1380: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x5080002b1400: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==1433924==ABORTING

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at pthread_kill.c:44
44            return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
(gdb) bt
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at pthread_kill.c:44
#1  __pthread_kill_internal (threadid=<optimized out>, signo=6) at pthread_kill.c:78
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at pthread_kill.c:89
#3  0x00007ffff73f68c2 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff73d9832 in __GI_abort () at abort.c:79
#5  0x00007ffff794f0ad in __sanitizer::Abort () at /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:143
#6  0x00007ffff7961de8 in __sanitizer::Die () at /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/sanitizer_common/sanitizer_termination.cpp:58
#7  0x00007ffff7931ad1 in __asan::ScopedInErrorReport::~ScopedInErrorReport (this=0x7fffffffc416)
    at /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/asan/asan_report.cpp:192
#8  0x00007ffff7931289 in __asan::ReportGenericError (pc=93824992243256, bp=bp@entry=140737488343184, sp=sp@entry=140737488343168, addr=88510688858568, is_write=is_write@entry=false,
    access_size=8, fatal=true, exp=<optimized out>) at /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/asan/asan_report.cpp:497
#9  0x00007ffff7931416 in __asan::ReportGenericError (pc=<optimized out>, bp=bp@entry=140737488343184, sp=sp@entry=140737488343168, addr=<optimized out>, is_write=is_write@entry=false,
    access_size=access_size@entry=8, exp=<optimized out>, fatal=true) at /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/asan/asan_report.cpp:497
#10 0x00007ffff79326f5 in __asan::__asan_report_load8 (addr=<optimized out>) at /usr/src/debug/sys-devel/gcc-15.0.9999/gcc-15.0.9999/libsanitizer/asan/asan_rtl.cpp:131
#11 0x0000555555556e38 in wmem_tree_foreach_nodes (node=node@entry=0x5080002b11c0, callback=callback@entry=0x555555554c90 <count_nodes>, user_data=user_data@entry=0x7ffff4809050)
    at /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:755
#12 0x0000555555573e35 in wmem_tree_foreach (tree=0x507000000200, callback=0x555555554c90 <count_nodes>, user_data=0x7ffff4809050) at /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:789
#13 wmem_tree_count (tree=0x507000000200) at /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:316
#14 wmem_test_tree () at /home/sam/git/wireshark/wsutil/wmem/wmem_test.c:1238
#15 0x00007ffff772075c in test_case_run (tc=<optimized out>) at ../glib-2.78.6/glib/gtestutils.c:3161
#16 g_test_run_suite_internal (suite=suite@entry=0x503000001810, path=0x7fffffffdc11 "/wmem/datastruct/tree") at ../glib-2.78.6/glib/gtestutils.c:3256
#17 0x00007ffff77204bb in g_test_run_suite_internal (suite=suite@entry=0x5030000014e0, path=0x7fffffffdc11 "/wmem/datastruct/tree") at ../glib-2.78.6/glib/gtestutils.c:3273
#18 0x00007ffff77204bb in g_test_run_suite_internal (suite=suite@entry=0x503000001450, path=0x7fffffffdc11 "/wmem/datastruct/tree") at ../glib-2.78.6/glib/gtestutils.c:3273
#19 0x00007ffff7720f4b in g_test_run_suite (suite=0x503000001450) at ../glib-2.78.6/glib/gtestutils.c:3352
#20 0x00007ffff772102c in g_test_run () at ../glib-2.78.6/glib/gtestutils.c:2462
#21 g_test_run () at ../glib-2.78.6/glib/gtestutils.c:2449
#22 0x00005555555549d2 in main (argc=<optimized out>, argv=<optimized out>) at /home/sam/git/wireshark/wsutil/wmem/wmem_test.c:1478
(gdb) frame 11
#11 0x0000555555556e38 in wmem_tree_foreach_nodes (node=node@entry=0x5080002b11c0, callback=callback@entry=0x555555554c90 <count_nodes>, user_data=user_data@entry=0x7ffff4809050)
    at /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:755
755         if (node->left) {
(gdb) p node
$1 = (wmem_tree_node_t *) 0x5080002b11c0
(gdb) p *node
$2 = {
  parent = 0x1a1a1a1a1a1a1a1a,
  left = 0x1a1a1a1a1a1a1a1a,
  right = 0x1a1a1a1a1a1a1a1a,
  key = 0x1a1a1a1a1a1a1a1a,
  data = 0x1a1a1a1a1a1a1a1a,
  color = (unknown: 0x1a1a1a1a),
  is_subtree = 26,
  is_removed = 26
}
Comment 1 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-10-20 14:10:29 UTC
(gdb) frame 12
#12 0x0000555555573e35 in wmem_tree_foreach (tree=0x507000000200, callback=0x555555554c90 <count_nodes>, user_data=0x7ffff4809050) at /home/sam/git/wireshark/wsutil/wmem/wmem_tree.c:789
warning: Source file is more recent than executable.
789         return wmem_tree_foreach_nodes(tree->root, callback, user_data

tree->root here is null but the check was removed
Comment 2 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-10-20 14:10:42 UTC
GCC 10 works, 11 doesn't, bisecting.
Comment 3 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-10-20 15:50:59 UTC
Started with r11-5391-gbb07490abba850
Comment 4 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-10-20 16:14:15 UTC
For completeness as well:
```
$ valgrind -q --track-origins=yes --expensive-definedness-checks=yes /home/sam/git/wireshark/build/run/wmem_test -r /wmem/datastruct/tree       17:13:50 [35/9734]
TAP version 13
# random seed: R02Seb9be78c033ae982ce8e953bddf09563
# Start of wmem tests
# Start of datastruct tests
==46919== Invalid read of size 8
==46919==    at 0x10927D: wmem_tree_foreach_nodes (wmem_tree.c:755)
==46919==    by 0x114370: UnknownInlinedFun (wmem_tree.c:789)
==46919==    by 0x114370: UnknownInlinedFun (wmem_tree.c:316)
==46919==    by 0x114370: wmem_test_tree (wmem_test.c:1238)
==46919==    by 0x4A2C75B: UnknownInlinedFun (gtestutils.c:3161)
==46919==    by 0x4A2C75B: g_test_run_suite_internal (gtestutils.c:3256)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2CF4A: g_test_run_suite (gtestutils.c:3352)
==46919==    by 0x4A2D02B: UnknownInlinedFun (gtestutils.c:2462)
==46919==    by 0x4A2D02B: g_test_run (gtestutils.c:2449)
==46919==    by 0x10878C: main (wmem_test.c:1478)
==46919==  Address 0x5a7ea78 is 40 bytes inside a block of size 88 free'd
==46919==    at 0x484BDEF: free (vg_replace_malloc.c:989)
==46919==    by 0x10ACCB: wmem_strict_free_all (wmem_allocator_strict.c:182)
==46919==    by 0x114354: UnknownInlinedFun (wmem_core.c:110)
==46919==    by 0x114354: wmem_test_tree (wmem_test.c:1237)
==46919==    by 0x4A2C75B: UnknownInlinedFun (gtestutils.c:3161)
==46919==    by 0x4A2C75B: g_test_run_suite_internal (gtestutils.c:3256)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2CF4A: g_test_run_suite (gtestutils.c:3352)
==46919==    by 0x4A2D02B: UnknownInlinedFun (gtestutils.c:2462)
==46919==    by 0x4A2D02B: g_test_run (gtestutils.c:2449)
==46919==    by 0x10878C: main (wmem_test.c:1478)
==46919==  Block was alloc'd at
==46919==    at 0x4848B93: malloc (vg_replace_malloc.c:446)
==46919==    by 0x49FA1AD: g_malloc (gmem.c:130)
==46919==    by 0x109DBF: UnknownInlinedFun (wmem_core.c:35)
==46919==    by 0x109DBF: wmem_strict_alloc (wmem_allocator_strict.c:81)
==46919==    by 0x109394: UnknownInlinedFun (wmem_core.c:44)
==46919==    by 0x109394: UnknownInlinedFun (wmem_tree.c:327)
==46919==    by 0x109394: lookup_or_insert32_node (wmem_tree.c:393)
==46919==    by 0x114297: UnknownInlinedFun (wmem_tree.c:412)
==46919==    by 0x114297: UnknownInlinedFun (wmem_tree.c:498)
==46919==    by 0x114297: wmem_test_tree (wmem_test.c:1233)
==46919==    by 0x4A2C75B: UnknownInlinedFun (gtestutils.c:3161)
==46919==    by 0x4A2C75B: g_test_run_suite_internal (gtestutils.c:3256)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2CF4A: g_test_run_suite (gtestutils.c:3352)
==46919==    by 0x4A2D02B: UnknownInlinedFun (gtestutils.c:2462)
==46919==    by 0x4A2D02B: g_test_run (gtestutils.c:2449)
==46919==    by 0x10878C: main (wmem_test.c:1478)
==46919==
==46919== Invalid read of size 8
==46919==    at 0x10927D: wmem_tree_foreach_nodes (wmem_tree.c:755)
==46919==    by 0x109290: wmem_tree_foreach_nodes (wmem_tree.c:756)
==46919==    by 0x114370: UnknownInlinedFun (wmem_tree.c:789)
==46919==    by 0x114370: UnknownInlinedFun (wmem_tree.c:316)
==46919==    by 0x114370: wmem_test_tree (wmem_test.c:1238)
==46919==    by 0x4A2C75B: UnknownInlinedFun (gtestutils.c:3161)
==46919==    by 0x4A2C75B: g_test_run_suite_internal (gtestutils.c:3256)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2CF4A: g_test_run_suite (gtestutils.c:3352)
==46919==    by 0x4A2D02B: UnknownInlinedFun (gtestutils.c:2462)
==46919==    by 0x4A2D02B: g_test_run (gtestutils.c:2449)
==46919==    by 0x10878C: main (wmem_test.c:1478)
==46919==  Address 0x1a1a1a1a1a1a1a22 is not stack'd, malloc'd or (recently) free'd
==46919==
==46919==
==46919== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==46919==  General Protection Fault
==46919==    at 0x10927D: wmem_tree_foreach_nodes (wmem_tree.c:755)
==46919==    by 0x109290: wmem_tree_foreach_nodes (wmem_tree.c:756)
==46919==    by 0x114370: UnknownInlinedFun (wmem_tree.c:789)
==46919==    by 0x114370: UnknownInlinedFun (wmem_tree.c:316)
==46919==    by 0x114370: wmem_test_tree (wmem_test.c:1238)
==46919==    by 0x4A2C75B: UnknownInlinedFun (gtestutils.c:3161)
==46919==    by 0x4A2C75B: g_test_run_suite_internal (gtestutils.c:3256)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2C4BA: g_test_run_suite_internal (gtestutils.c:3273)
==46919==    by 0x4A2CF4A: g_test_run_suite (gtestutils.c:3352)
==46919==    by 0x4A2D02B: UnknownInlinedFun (gtestutils.c:2462)
==46919==    by 0x4A2D02B: g_test_run (gtestutils.c:2449)
==46919==    by 0x10878C: main (wmem_test.c:1478)
Segmentation fault         (core dumped) valgrind -q --track-origins=yes --expensive-definedness-checks=yes /home/sam/git/wireshark/build/run/wmem_test -r /wmem/datastruct/tree
```
Comment 5 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-10-22 06:08:50 UTC
```
 /**
  * return inserted node
  */
+__attribute__((noipa))
 static wmem_tree_node_t *
 lookup_or_insert32_node(wmem_tree_t *tree, uint32_t key,
         void*(*func)(void*), void* data, bool is_subtree, bool replace)

```

is enough to suppress it (first had rb_insert_case1+lookup_or_insert32_node surrounded with no-sa pragma)
Comment 6 Holger Hoffstätte 2025-03-06 10:08:18 UTC
Sam's linked MR was merged, so I decided to retry with LTO.

- I added the MR patch to 4.4.5 (since we know 4.4.5 passes all tests)
- disabled filter-lto, explicitly enabled -DENABLE_LTO=ON
  (this should probably be automagic)
- enabled LTO via package.env

This built correctly using gcc-14.2.1_p20250301.

Both executable and libwireshark are quite a bit smaller, and the
resulting executable seems to work fine: I started a capture,
drilled down into packets etc. without problem, no crashes.

Running the test suite says:

  === 837 passed, 62 skipped, 5 warnings in 25.99s ====

Looks good!
Comment 7 Holger Hoffstätte 2025-03-06 10:12:00 UTC
*** Bug 754021 has been marked as a duplicate of this bug. ***
Comment 8 Holger Hoffstätte 2025-03-06 11:31:02 UTC
(In reply to Holger Hoffstätte from comment #6)
> - disabled filter-lto, explicitly enabled -DENABLE_LTO=ON
>   (this should probably be automagic)

Maybe something like

    if tc-is-lto; then
        mycmakeargs+=( -DENABLE_LTO=ON )
    fi

Seems to work. Not sure if it is even necessary.
Comment 9 Eli Schwartz gentoo-dev 2025-03-06 16:14:24 UTC
As far as I can tell there is zero purpose of -DENABLE_LTO=ON, since all it does is compile a test program to see whether the compiler implements LTO, then update the CMAKE_BUILD_TYPE=Release / RelWithDebInfo flags to utilize LTO.

While technically this doesn't "matter" for the eclass defaults, translating -flto into ENABLE_LTO would do one of two things:

- cause -flto to be passed multiple times, if you don't then filter-lto
- break users who configure CMAKE_BUILD_TYPE manually, if you do filter-lto
Comment 10 Holger Hoffstätte 2025-03-06 16:37:34 UTC
(In reply to Eli Schwartz from comment #9)
> As far as I can tell there is zero purpose of -DENABLE_LTO=ON, since all it
> does is compile a test program to see whether the compiler implements LTO,
> then update the CMAKE_BUILD_TYPE=Release / RelWithDebInfo flags to utilize
> LTO.

Yup, saw that. My idea here was that IF the user has enabled LTO we should at least try to play nice with the build system. It seemed odd to me that enabling LTO would let cmake's configure phase say that LTO is disabled, even if normal emerge runs will not show this.

> While technically this doesn't "matter" for the eclass defaults, translating
> -flto into ENABLE_LTO would do one of two things:
> 
> - cause -flto to be passed multiple times, if you don't then filter-lto

We want to get rid of filter-lto, and I verified that it does not pass -flto multiple times during compilation; it uses exactly the values I set in package.env. Either way the output is correct and what one would expect.

I was more confused that it's apparently not possible to use an inline expression like -DENABLE_LTO=$(tc-is-lto) - which is used in the tree but apparently does not work at all, hence the conditional block.
Comment 11 Eli Schwartz gentoo-dev 2025-03-06 18:01:07 UTC
(In reply to Holger Hoffstätte from comment #10)
> (In reply to Eli Schwartz from comment #9)
> > As far as I can tell there is zero purpose of -DENABLE_LTO=ON, since all it
> > does is compile a test program to see whether the compiler implements LTO,
> > then update the CMAKE_BUILD_TYPE=Release / RelWithDebInfo flags to utilize
> > LTO.
> 
> Yup, saw that. My idea here was that IF the user has enabled LTO we should
> at least try to play nice with the build system. It seemed odd to me that
> enabling LTO would let cmake's configure phase say that LTO is disabled,
> even if normal emerge runs will not show this.


cmake's configuration phase says loads of things nobody pays any attention to at all.

It is very true that cmake IPO isn't enabled, it just has no bearing on whether the source code is compiled with LTO.


> > While technically this doesn't "matter" for the eclass defaults, translating
> > -flto into ENABLE_LTO would do one of two things:
> > 
> > - cause -flto to be passed multiple times, if you don't then filter-lto
> 
> We want to get rid of filter-lto, and I verified that it does not pass -flto
> multiple times during compilation; it uses exactly the values I set in
> package.env. Either way the output is correct and what one would expect.


I tested this and if I pass -DENABLE_LTO=ON without -flto in *FLAGS, cmake prints: 

-- Using "Ninja" generator and build type "RelWithDebInfo"
-- LTO/IPO is enabled for Release configuration


but no files are compiled with -flto. So, it's not passing anything at all. Heck if I know why.


> I was more confused that it's apparently not possible to use an inline
> expression like -DENABLE_LTO=$(tc-is-lto) - which is used in the tree but
> apparently does not work at all, hence the conditional block.


Because tc-is-lto is an ebuild function, and returns a bash true/false status (an exitcode, specifically) rather than a text string which no build systems other than cmake comprehend. You need to translate a bash truth value to a cmake command line text string.
Comment 12 Holger Hoffstätte 2025-04-16 18:44:40 UTC
FWIW Sam's patch has been backported to 4.4.x with the just-released 4.4.6. Giving that a try and then a PR.
Comment 13 Larry the Git Cow gentoo-dev 2025-04-17 13:03:28 UTC
The bug has been closed via the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=271d5459ef4a511414f2f968afe4c728fa5664b7

commit 271d5459ef4a511414f2f968afe4c728fa5664b7
Author:     Holger Hoffstätte <holger@applied-asynchrony.com>
AuthorDate: 2025-04-17 09:53:02 +0000
Commit:     Sam James <sam@gentoo.org>
CommitDate: 2025-04-17 13:02:35 +0000

    net-analyzer/wireshark: add 4.4.6, drop py3.10, allow LTO again
    
    Bug: https://bugs.gentoo.org/754021
    Closes: https://bugs.gentoo.org/941890
    Signed-off-by: Holger Hoffstätte <holger@applied-asynchrony.com>
    Signed-off-by: Sam James <sam@gentoo.org>

 net-analyzer/wireshark/Manifest               |   2 +
 net-analyzer/wireshark/wireshark-4.4.6.ebuild | 328 ++++++++++++++++++++++++++
 2 files changed, 330 insertions(+)

Additionally, it has been referenced in the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=71a7e7c01404fe221bb9763dd3d4f58f5a701984

commit 71a7e7c01404fe221bb9763dd3d4f58f5a701984
Author:     Holger Hoffstätte <holger@applied-asynchrony.com>
AuthorDate: 2025-04-17 09:59:39 +0000
Commit:     Sam James <sam@gentoo.org>
CommitDate: 2025-04-17 13:02:45 +0000

    net-analyzer/wireshark: drop py3.10, allow LTO again in -9999
    
    Bug: https://bugs.gentoo.org/754021
    Bug: https://bugs.gentoo.org/941890
    Signed-off-by: Holger Hoffstätte <holger@applied-asynchrony.com>
    Closes: https://github.com/gentoo/gentoo/pull/41627
    Signed-off-by: Sam James <sam@gentoo.org>

 net-analyzer/wireshark/wireshark-9999.ebuild | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)
Comment 14 Larry the Git Cow gentoo-dev 2025-04-18 04:23:30 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=fad8ff8a45afc83559f8df695cf96dfec51d3e8a

commit fad8ff8a45afc83559f8df695cf96dfec51d3e8a
Author:     Sam James <sam@gentoo.org>
AuthorDate: 2025-04-18 04:21:42 +0000
Commit:     Sam James <sam@gentoo.org>
CommitDate: 2025-04-18 04:23:01 +0000

    net-analyzer/wireshark: fix runtime with LTO
    
    Qt's qcompilerdetection.h currently checks for whether -fPIE is being used
    along with QT_USE_PROTECTED_VISIBILITY ("reduce relocations", which Qt
    automatically uses if supported). It bails out if -fPIE is used, as -fPIC
    is required instead.
    
    If LTO is used, when one does something like:
    (1) g++ -c -flto -fPIC qtlto.cc
    (2) g++     -pie -fPIE qtlto.o -o qtlto
    
    At point (1), the Qt check in the headers fires, and everything is fine,
    because we're indeed using -fPIC, and GCC doesn't automatically add -fPIE
    when built with --enable-default-pie if -fPIC is present on the command line.
    
    GCC may apply optimisations at this point given Qt is using -mno-direct-extern-access
    and it was built with -fPIC not -fPIE.
    
    Later, at point (2), -fPIE is passed. This happens in Wireshark because
    `CMAKE_POSITION_INDEPENDENT_CODE` gets set in CMakeLists.txt. With LTO,
    there's no opportunity for the Qt sanity check in headers to fire again,
    as everything is already long-preprocessed and GCC will have applied some
    optimisations already assuming the -fPIC code model in (1). But as slyfox
    says at https://bugs.gentoo.org/754021#c12, GCC merges -fPIC -fPIE to -fPIE
    at LTO-time (-fPIC coming from the earlier LTO object in (1), and -fPIE
    was just-passed on the command line).
    
    qtlto (or Wireshark) then crashes. For Wireshark, this looks like:
    ```
     #0  0x00007ff40e529cf0 in QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData> >::get (this=<optimized out>)
         at /usr/src/debug/dev-qt/qtbase-6.8.3/qtbase-everywhere-src-6.8.3/src/corelib/tools/qscopedpointer.h:112
     #1  qGetPtrHelper<QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData> > > (ptr=<optimized out>)
         at /usr/src/debug/dev-qt/qtbase-6.8.3/qtbase-everywhere-src-6.8.3/src/corelib/global/qtclasshelpermacros.h:128
     #2  QObject::d_func (this=<optimized out>) at /usr/src/debug/dev-qt/qtbase-6.8.3/qtbase-everywhere-src-6.8.3/src/corelib/kernel/qobject.h:108
     #3  QObjectPrivate::get (o=<optimized out>) at /usr/src/debug/dev-qt/qtbase-6.8.3/qtbase-everywhere-src-6.8.3/src/corelib/kernel/qobject_p.h:150
     #4  doActivate<false> (sender=0x0, signal_index=9, argv=argv@entry=0x7ffe59a73c30) at /usr/src/debug/dev-qt/qtbase-6.8.3/qtbase-everywhere-src-6.8.3/src/corelib/kernel/qobject.cpp:4003
     #5  0x00007ff40e4d2809 in QMetaObject::activate
         (sender=<optimized out>, m=m@entry=0x7ff40f44f6c0 <QGuiApplication::staticMetaObject>, local_signal_index=local_signal_index@entry=1, argv=argv@entry=0x7ffe59a73c30)
         at /usr/src/debug/dev-qt/qtbase-6.8.3/qtbase-everywhere-src-6.8.3/src/corelib/kernel/qobject.cpp:4183
     #6  0x00007ff40ead5676 in QGuiApplication::screenAdded (this=<optimized out>, _t1=<optimized out>)
    [...]
    ```
    
    We need to drop -fPIE somehow at link-time accordingly. There's a few
    ways of doing this but I've gone for not calling `check_pie_supported()`
    (see (7) below).
    
    (Analysis on fixing this in other packages may depend on whether any static
    libraries *installed* by CMake where -fPIC was no longer passed for those,
    we would have a problem. I'd tried to use POSITION_INDEPENDENT_CODE at first
    but then -fPIC gets dropped as well everywhere, and setting the target
    property to false for just the Wireshark executable also doesn't work
    because it'll pass -no-pie which isn't what we want.)
    
    There are some questions:
    (3) Why doesn't this happen with Clang, given that Clang has -fno-direct-access-external-data
        (equivalent to GCC's -mno-direct-extern-access), even when Qt is built
        with bfd (not lld)?
    
        The answer seems to be that Clang doesn't implement the optimisation
        yet to avoid copy-relocations where possible. GCC implemented that in
        5.x in r5-5573-g77ad54d911dd7c.
    
    (4) Why doesn't this (seem to) happen in other distributions?
    
        nextcloud-client suffers from the same issue analysed here, see
        https://bugs.gentoo.org/933110. The upstream bug at https://github.com/nextcloud/desktop/issues/2790
        was reported by a Debian developer (cgzones), so it's a reasonable assumption
        that it can happen on Debian.
    
        Debian is one of few distributions (we're another) to use --enable-default-pie
        in GCC rather than just passing it to all package builds in the package manager:
        it's possible that some distros are just disabling -fPIE or adding a workaround
        like we did for https://bugs.gentoo.org/552440. Not many distros build
        with LTO either.
    
        Debian also stopped building Wireshark with LTO because of a bug in Wireshark
        itself (https://bugs.gentoo.org/941890), so I guess they disabled LTO
        and didn't notice this crash.
    
        (This is enough for me to be more confident in my analysis, anyway.)
    
    (5) Could Qt communicate this somehow automatically?
    
        I think it might be able to if statically linking Qt and Qt was built
        with LTO.
    
        Otherwise, I think the only option would be an ELF .note. pkg-config
        could maybe work but you can't assume all Qt consumers use that...
    
        See the discussion around <https://bugreports.qt.io/browse/QTBUG-45755?focusedId=282483&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-282483>:
        > Thiago Macieira added a comment - 22 May '15 17:11
        > There aren't that many autoconf-based Qt5 builds and we've never exported the flag anyway.
    
        (It might be worth bringing this .note idea up to Thiago and/or H.J. but
        I'm not sure yet if it'll work.)
    
        On the Qt side, -fPIC gets passed in to various places before because
        Qt's CMake config files have INTERFACE_COMPILE_OPTIONS w/ -fPIC. Maybe
        the answer is for Qt packages to never use CMAKE_POSITION_INDEPENDENT_CODE
        instead. This came up in https://gitlab.kitware.com/cmake/cmake/-/issues/15570.
    
    (6) Could we just disable "reduce relocations" in Qt itself, given that
        the workaround here will need to be applied in various Qt consumers?
    
        This would significantly impact startup times of applications using Qt
        and there don't seem to be too many applications doing this (only 2
        known so far in Gentoo: Wireshark and nextcloud-client).
    
    (7) Is the mechanism used to fix this brittle?
    
        Yes, we're relying on a CMake bug/feature for now at https://gitlab.kitware.com/cmake/cmake/-/issues/25588
        so it doesn't try to enable *or* disable PIE at link-time and we can
        just rely on our toolchain defaults.
    
    Thanks to Arusekk for producing a minimal example and reporting it upstream
    to Wireshark, thanks to slyfox for analysing the interaction with LTO, thanks
    to Holger for the discussion around it and testing, and thanks to Eli for
    reviewing the commit message.
    
    Bug: https://bugs.gentoo.org/552440
    Bug: https://bugs.gentoo.org/754021
    Bug: https://bugs.gentoo.org/933110
    Bug: https://bugs.gentoo.org/941890
    Bug: https://gitlab.kitware.com/cmake/cmake/-/issues/15570
    Bug: https://gitlab.kitware.com/cmake/cmake/-/issues/25588
    Bug: https://gitlab.kitware.com/cmake/cmake/-/issues/23980
    Bug: https://gitlab.com/wireshark/wireshark/-/issues/17040
    Bug: https://bugreports.qt.io/browse/QTBUG-45755
    Bug: https://bugreports.qt.io/browse/QTBUG-47942
    Bug: https://gcc.gnu.org/PR65248
    Bug: https://gcc.gnu.org/PR65886
    Thanks-to: Arusekk <arek_koz@o2.pl>
    Thanks-to: Sergei Trofimovich <slyfox@gentoo.org>
    Thanks-to: Holger Hoffstätte <holger@applied-asynchrony.com>
    Thanks-to: Eli Schwartz <eschwartz@gentoo.org>
    Signed-off-by: Sam James <sam@gentoo.org>

 net-analyzer/wireshark/files/4.4.6-lto.patch       | 164 +++++++++++++++++++++
 ...hark-4.4.6.ebuild => wireshark-4.4.6-r1.ebuild} |  11 +-
 net-analyzer/wireshark/wireshark-9999.ebuild       |  11 +-
 3 files changed, 175 insertions(+), 11 deletions(-)