Bug 515183 - Error occurred while executing the command `valgrind --num-callers=1 ./hello_world`
Summary: Error occurred while executing the command `valgrind --num-callers=1 ./hello_...
Status: REPORTED
Alias: None
Product: valgrind
Classification: Developer tools
Component: memcheck (other bugs)
Version First Reported In: 3.25.1
Platform: Other Linux
: NOR normal
Target Milestone: ---
Assignee: Paul Floyd
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2026-01-28 03:32 UTC by daxin
Modified: 2026-01-29 09:41 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed/Implemented In:
Sentry Crash Report:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description daxin 2026-01-28 03:32:26 UTC
SUMMARY
Error occurred while executing the command `valgrind --num-callers=1 ./hello_world`

STEPS TO REPRODUCE
1. dnf install -y  valgrind glibc-devel glibc-debuginfo gcc-c++
2. cat hello_world.cpp
" 
#include <iostream>

int main() {
    std::cout << "hello world" << std::endl;
    return 0;
}
"
3. g++ -o hello_world hello_world.cpp
4. valgrind --num-callers=1  ./hello_world

OBSERVED RESULT
[root@localhost valgrind]# valgrind --num-callers=1 ./hello_world
==38337== Memcheck, a memory error detector
==38337== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==38337== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info
==38337== Command: ./hello_world
==38337==
==38337== FATAL: in suppressions file "/usr/libexec/valgrind/default.supp" near line 1589:
==38337==    suppression must contain at least one location line which is not "..."
==38337== exiting now.

EXPECTED RESULT
[root@localhost valgrind]# valgrind --num-callers=1 ./hello_world
==38340== Memcheck, a memory error detector
==38340== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==38340== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info
==38340== Command: ./hello_world
==38340==
hello world
==38340==
==38340== HEAP SUMMARY:
==38340==     in use at exit: 0 bytes in 0 blocks
==38340==   total heap usage: 2 allocs, 2 frees, 73,728 bytes allocated
==38340==
==38340== All heap blocks were freed -- no leaks are possible
==38340==
==38340== For lists of detected and suppressed errors, rerun with: -s
==38340== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[root@localhost valgrind]# echo $?
0

ADDITIONAL INFORMATION
https://sourceware.org/git/?p=valgrind.git;a=commitdiff;h=758ab5e6d22fb80b17e6888d03e065955f579735
Comment 1 Paul Floyd 2026-01-28 10:05:29 UTC
Stanza causing this
{
  dtv-addr-init
  Memcheck:Leak
  match-leak-kinds: possible,reachable
  ...
  fun:allocate_dtv_entry
  fun:allocate_and_init
  fun:tls_get_addr_tail*
  fun:__tls_get_addr
}

Helgrind and DRD have quite a few suppressions that have ... in the first line.

Should we restrict --num-callers to at least 2?

Leak suppression would only match the allocation function. That means that either all allocations by malloc etc get suppressed or none.
Comment 2 daxin 2026-01-28 10:32:58 UTC
(In reply to Paul Floyd from comment #1)
> Stanza causing this
> {
>   dtv-addr-init
>   Memcheck:Leak
>   match-leak-kinds: possible,reachable
>   ...
>   fun:allocate_dtv_entry
>   fun:allocate_and_init
>   fun:tls_get_addr_tail*
>   fun:__tls_get_addr
> }
> 
> Helgrind and DRD have quite a few suppressions that have ... in the first
> line.
> 
> Should we restrict --num-callers to at least 2?
> 
> Leak suppression would only match the allocation function. That means that
> either all allocations by malloc etc get suppressed or none.

Referring to the logic in the commit https://github.com/LouisBrunner/valgrind-macos/commit/d74a2608e59d16033673ecdf85961ebe1db2e2da, does it retain the original fun:malloc line and then add new ...  wildcards for multi-level malloc matching? Specifically, it is shown as follows:
{
  dtv-addr-init
  Memcheck:Leak
  match-leak-kinds: possible,reachable
  fun:malloc
  ...
  fun:allocate_dtv_entry
  fun:allocate_and_init
  fun:tls_get_addr_tail*
  fun:__tls_get_addr
}

Following the above instructions, executing the command `valgrind --num-callers=1 ./hello_world` will not produce any errors.
Comment 3 Paul Floyd 2026-01-28 11:08:20 UTC
Why do you want to use --num-callers=1?
Comment 4 Paul Floyd 2026-01-28 11:12:32 UTC
(In reply to daxin from comment #2)

> Referring to the logic in the commit
> https://github.com/LouisBrunner/valgrind-macos/commit/
> d74a2608e59d16033673ecdf85961ebe1db2e2da, does it retain the original
> fun:malloc line and then add new ...  wildcards for multi-level malloc
> matching? Specifically, it is shown as follows:
> {
>   dtv-addr-init
>   Memcheck:Leak
>   match-leak-kinds: possible,reachable
>   fun:malloc
>   ...

We could do something like that. First we need to make sure which allocation function is used there.
Comment 5 Paul Floyd 2026-01-28 11:25:51 UTC
Looks like it is malloc. I need to retest on Arch to see what was happening there - I didn't record the callstack that lead to me broadening this suppression.
Comment 6 daxin 2026-01-29 02:00:31 UTC
(In reply to Paul Floyd from comment #3)
> Why do you want to use --num-callers=1?

Historical versions used --num-callers=1 to execute the test and pass. However, starting from version 3.23.0, using --num-callers=1 to execute the test results in failure. I would like to inquire whether the commit at https://github.com/LouisBrunner/valgrind-macos/commit/758ab5e6d22fb80b17e6888d03e065955f579735 is reasonable?

Or, I would like to understand why the current 3.25.1 version causes the test to fail when using --num-callers=1, and whether there is a method to solve this problem.
Comment 7 Paul Floyd 2026-01-29 09:33:47 UTC
(In reply to daxin from comment #6)

> Historical versions used --num-callers=1 to execute the test and pass.

That doesn't mean that it made any sense or was useful in a general way.

Take this example

#include <stdlib.h>

int main(void)
{
   // deliberately leak 4Gbytes
   int* pi = malloc(1000000000*sizeof(*pi));
   pi = NULL;
}

With the default num-callers and --leak-check=full that gives

==468== HEAP SUMMARY:
==468==     in use at exit: 4,000,000,000 bytes in 1 blocks
==468==   total heap usage: 1 allocs, 0 frees, 4,000,000,000 bytes allocated
==468==
==468== 4,000,000,000 bytes in 1 blocks are possibly lost in loss record 1 of 1
==468==    at 0x483EA32: malloc (vg_replace_malloc.c:447)
==468==    by 0x40047A: main (bigleak.c:6)
==468==
==468== LEAK SUMMARY:
==468==    definitely lost: 0 bytes in 0 blocks
==468==    indirectly lost: 0 bytes in 0 blocks
==468==      possibly lost: 4,000,000,000 bytes in 1 blocks
==468==    still reachable: 0 bytes in 0 blocks
==468==         suppressed: 0 bytes in 0 blocks
==468==
==468== For lists of detected and suppressed errors, rerun with: -s
==468== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

If I "fix" the default suppression to allow --num-callers=1 then I get

==453== HEAP SUMMARY:
==453==     in use at exit: 4,000,000,000 bytes in 1 blocks
==453==   total heap usage: 1 allocs, 0 frees, 4,000,000,000 bytes allocated
==453==
==453== LEAK SUMMARY:
==453==    definitely lost: 0 bytes in 0 blocks
==453==    indirectly lost: 0 bytes in 0 blocks
==453==      possibly lost: 0 bytes in 0 blocks
==453==    still reachable: 0 bytes in 0 blocks
==453==         suppressed: 4,000,000,000 bytes in 1 blocks
==453==
==453== For lists of detected and suppressed errors, rerun with: -s
==453== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Both DRD and Helgrind have several default suppressions with ... at the top level of the callstack on all platforms.

Darwin memcheck has quite a few top level ... suppressions, none for FreeBSD or Solaris.

There are two reasons why we use wildcards in suppressions.
1. To avoid having to write many explicit suppressions.
2. To make the suppressions more robust and future proof. We regularly need to update the suppressions due to changes in the various libc/libpthread implementations. Without wildcards that would happen more often.

It looks to me as though your issue is with a small artificial testcase rather than a real world production application.

Making 2 the lower limit for --num-callers is a trivial change. That would give

$ ./vg-in-place --tool=drd --num-callers=1 helgrind/tests/hg01_all_ok
valgrind: Bad option: --num-callers=1
valgrind: '--num-callers' argument must be between 2 and 500
valgrind: Use --help for more information or consult the user manual.
Comment 8 daxin 2026-01-29 09:41:13 UTC
(In reply to Paul Floyd from comment #7)
> (In reply to daxin from comment #6)
> 
> > Historical versions used --num-callers=1 to execute the test and pass.
> 
> That doesn't mean that it made any sense or was useful in a general way.
> 
> Take this example
> 
> #include <stdlib.h>
> 
> int main(void)
> {
>    // deliberately leak 4Gbytes
>    int* pi = malloc(1000000000*sizeof(*pi));
>    pi = NULL;
> }
> 
> With the default num-callers and --leak-check=full that gives
> 
> ==468== HEAP SUMMARY:
> ==468==     in use at exit: 4,000,000,000 bytes in 1 blocks
> ==468==   total heap usage: 1 allocs, 0 frees, 4,000,000,000 bytes allocated
> ==468==
> ==468== 4,000,000,000 bytes in 1 blocks are possibly lost in loss record 1
> of 1
> ==468==    at 0x483EA32: malloc (vg_replace_malloc.c:447)
> ==468==    by 0x40047A: main (bigleak.c:6)
> ==468==
> ==468== LEAK SUMMARY:
> ==468==    definitely lost: 0 bytes in 0 blocks
> ==468==    indirectly lost: 0 bytes in 0 blocks
> ==468==      possibly lost: 4,000,000,000 bytes in 1 blocks
> ==468==    still reachable: 0 bytes in 0 blocks
> ==468==         suppressed: 0 bytes in 0 blocks
> ==468==
> ==468== For lists of detected and suppressed errors, rerun with: -s
> ==468== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
> 
> If I "fix" the default suppression to allow --num-callers=1 then I get
> 
> ==453== HEAP SUMMARY:
> ==453==     in use at exit: 4,000,000,000 bytes in 1 blocks
> ==453==   total heap usage: 1 allocs, 0 frees, 4,000,000,000 bytes allocated
> ==453==
> ==453== LEAK SUMMARY:
> ==453==    definitely lost: 0 bytes in 0 blocks
> ==453==    indirectly lost: 0 bytes in 0 blocks
> ==453==      possibly lost: 0 bytes in 0 blocks
> ==453==    still reachable: 0 bytes in 0 blocks
> ==453==         suppressed: 4,000,000,000 bytes in 1 blocks
> ==453==
> ==453== For lists of detected and suppressed errors, rerun with: -s
> ==453== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
> 
> Both DRD and Helgrind have several default suppressions with ... at the top
> level of the callstack on all platforms.
> 
> Darwin memcheck has quite a few top level ... suppressions, none for FreeBSD
> or Solaris.
> 
> There are two reasons why we use wildcards in suppressions.
> 1. To avoid having to write many explicit suppressions.
> 2. To make the suppressions more robust and future proof. We regularly need
> to update the suppressions due to changes in the various libc/libpthread
> implementations. Without wildcards that would happen more often.
> 
> It looks to me as though your issue is with a small artificial testcase
> rather than a real world production application.
> 
> Making 2 the lower limit for --num-callers is a trivial change. That would
> give
> 
> $ ./vg-in-place --tool=drd --num-callers=1 helgrind/tests/hg01_all_ok
> valgrind: Bad option: --num-callers=1
> valgrind: '--num-callers' argument must be between 2 and 500
> valgrind: Use --help for more information or consult the user manual.

ok, thank you for your answer, it was very helpful to me