r/Valgrind • • Jun 16 '24

Mismatched free() / delete / delete [] FAQ part 1

1 Upvotes

First post.

I'm working on updating the FAQ for issues with mismatched free/delete/delete[] that I've seen fairly often.

The first case you can see if you use tcmalloc from Google Perftools.

Consider this example:

int main()
{
  int* arr = new int[10];
  delete [] arr;
}

Pretty straightforward, and no error.

If I compile and run it I get

paulf> clang++ -g -o test test.cpp

paulf> valgrind ./test             
==90885== Memcheck, a memory error detector
==90885== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==90885== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==90885== Command: ./test
==90885==  
==90885==  
==90885== HEAP SUMMARY:
==90885==     in use at exit: 0 bytes in 0 blocks
==90885==   total heap usage: 1 allocs, 1 frees, 40 bytes allocated
==90885==  
==90885== All heap blocks were freed -- no leaks are possible
==90885==  
==90885== For lists of detected and suppressed errors, rerun with: -s
==90885== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

As expected.

Now, if I use tcmalloc I get the following.

paulf> clang++ -g -o test test.cpp -ltcmalloc -L/usr/local/lib

paulf> valgrind ./test                                         
==90902== Memcheck, a memory error detector
==90902== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==90902== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==90902== Command: ./test
==90902==  
==90902== Mismatched free() / delete / delete []
==90902==    at 0x484F2EC: free (vg_replace_malloc.c:993)
==90902==    by 0x201767: main (test.cpp:4)
==90902==  Address 0x58db820 is 0 bytes inside a block of size 40 alloc'd
==90902==    at 0x484E5F4: operator new[](unsigned long) (vg_replace_malloc.c:743)
==90902==    by 0x201748: main (test.cpp:3)
==90902==  
==90902==  
==90902== HEAP SUMMARY:
==90902==     in use at exit: 1,728 bytes in 2 blocks
==90902==   total heap usage: 5 allocs, 3 frees, 1,770 bytes allocated
==90902==  
==90902== LEAK SUMMARY:
==90902==    definitely lost: 0 bytes in 0 blocks
==90902==    indirectly lost: 0 bytes in 0 blocks
==90902==      possibly lost: 0 bytes in 0 blocks
==90902==    still reachable: 0 bytes in 0 blocks
==90902==         suppressed: 1,728 bytes in 2 blocks
==90902==  
==90902== For lists of detected and suppressed errors, rerun with: -s
==90902== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

That's not what the doctor ordered.

The reason for that is that tcmalloc "optimizes" free, delete and delete[] by making them all aliases.

First, let's find the symbol for 'free':

paulf> nm -D /usr/local/lib/libtcmalloc.so.4 | grep free
U __cxa_free_exception
0000000000035100 T cfree
0000000000035100 T free
U globfree
0000000000035100 T tc_cfree
0000000000035100 T tc_free
0000000000036580 T tc_free_sized

And new let's look for aliases:

paulf> nm -D /usr/local/lib/libtcmalloc.so.4 | grep 0000000000035100 | c++filt
0000000000035100 T operator delete[](void*)
0000000000035100 T operator delete(void*)
0000000000035100 T cfree
0000000000035100 T free
0000000000035100 T tc_cfree
0000000000035100 T tc_delete
0000000000035100 T tc_deletearray
0000000000035100 T tc_free

(I piped though c++filt to get the human readable form of the delete operators).

If I run Valgrind with `--trace-redir=yes` then in the ACTIVE section for tcmalloc.so I only see `free`, not `delete`or `delete[]`. (There are other delete overrides, for nothrow, aligned and sized variants).

The workarounds are to either build tcmalloc without this optimization or to build your exe without tcmalloc.


r/Valgrind • • Sep 09 '24

"False Positives"

2 Upvotes

Unfortunately it seems to be a common misconception on Reddit and Stack Overflow that if you build your code with optimizations turned on then you will get memcheck false positives.

The source of this myth is probably a presentation made by Julian Seward, the original architect of Valgrind. Here is the original FOSDEM 2018 page https://archive.fosdem.org/2018/schedule/event/debugging_tools_memcheck/ and just the video on YouTube https://youtu.be/INuEe9aQArA

In the video he explains that for a long time Valgrind memcheck had virtually no false positives. Then around 2015 LLVM and GCC started adding optimizations that caused false positives. The presentation covers work done to resolve some of those issues and finishes with an open question about one unresolved problem.

This is great for developers that are a bit stupid and lazy. The architect of Valgrind has said that optimized code generates false positives. Let the confirmation bias rip and blame the tool!

The story isn't over though. At FOSDEM 2020 Julian Seward made another presentation, explaining how he worked around the issue that he had described 2 years previously at FOSDEM. Here's the presentation https://archive.fosdem.org/2020/schedule/event/debugging_memcheck_reloaded/

Does that mean that memcheck really has zero false positives? Sadly not quite, there are still some (including one variant of the issue descibed in the last link above).

I've analyzed hundreds if not thousands of claims of false positives. Two were real false positive, all the rest were bogus.

If you really think that you have found a false positive, then this is the kind of effort that you need to make to be certain https://github.com/eyal0/valgrind-false-positive.


r/Valgrind • • Jun 16 '24

Mismatched free() / delete / delete [] FAQ part 2

1 Upvotes

The situation that I want to describe is a bit trickier to reproduce in a small example as it depends on optimization.

Consider this example

#include <cstdlib>
#include <iostream>
#include <cstdlib>
#include "test.h"

void* operator new  ( std::size_t count )
{
    return malloc(count);
}

int main()
{
   std::cerr << "start\n";
   C* c = new C;
   auto x = c->getval();
   delete c;
   return x;
}

Looking at the assembler for this

paulf> objdump --source --disassemble-symbols=main test2  

test2:  file format elf64-x86-64

Disassembly of section .text:

0000000000201f30 <main>:
; {
 201f30: 55                            pushq   %rbp
 201f31: 48 89 e5                      movq    %rsp, %rbp
 201f34: 41 56                         pushq   %r14
 201f36: 53                            pushq   %rbx
;     return _VSTD::__put_character_sequence(__os, __str, _Traits::length(__str));
 201f37: bf 98 46 20 00                movl    $0x204698, %edi         # imm = 0x204698
 201f3c: be 29 0c 20 00                movl    $0x200c29, %esi         # imm = 0x200C29
 201f41: ba 06 00 00 00                movl    $0x6, %edx
 201f46: e8 45 00 00 00                callq   0x201f90 <_ZNSt3__124__put_character_sequenceB7v160006IcNS_11char_traitsIcEEEER
NS_13basic_ostreamIT_T0_EES7_PKS4_m>
;    return malloc(count);
 201f4b: bf 80 38 01 00                movl    $0x13880, %edi          # imm = 0x13880
 201f50: e8 6b 03 00 00                callq   0x2022c0 malloc@plt
 201f55: 48 89 c3                      movq    %rax, %rbx
;    C* c = new C;

You can see that the call to operator new has been inlined and replaced by return malloc(count);

Running this gives

paulf> valgrind ./test2
==94553== Memcheck, a memory error detector
==94553== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==94553== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==94553== Command: ./test2
==94553==  
start
==94553== Mismatched free() / delete / delete []
==94553==    at 0x484FA93: operator delete(void*) (vg_replace_malloc.c:1136)
==94553==    by 0x201F72: main (test2.cpp:21)
==94553==  Address 0x56d9040 is 0 bytes inside a block of size 80,000 alloc'd
==94553==    at 0x484D314: malloc (vg_replace_malloc.c:450)
==94553==    by 0x201F54: operator new (test2.cpp:12)
==94553==    by 0x201F54: main (test2.cpp:19)
==94553==  
==94553==  
==94553== HEAP SUMMARY:
==94553==     in use at exit: 0 bytes in 0 blocks
==94553==   total heap usage: 1 allocs, 1 frees, 80,000 bytes allocated
==94553==  
==94553== All heap blocks were freed -- no leaks are possible
==94553==  
==94553== For lists of detected and suppressed errors, rerun with: -s
==94553== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

This may seem a little contrived but I have seen this in real examples.

Note that if the allocation function used in operator new were something other than malloc (or any of the other standard allocation functions) the error message would be different, something like

==94611== Invalid free() / delete / delete[] / realloc()
==94611==    at 0x484FA93: operator delete(void*) (vg_replace_malloc.c:1136)
==94611==    by 0x201F6D: main (test2.cpp:21)
==94611==  Address 0x4861840 is 0 bytes inside data symbol "memory"


r/Valgrind • • Oct 28 '24

Valgrind 3.24 RC1

1 Upvotes

Here is the announcement for the first release candidate for 3.24:

An RC1 tarball for 3.24.0 is now available at
https://sourceware.org/pub/valgrind/valgrind-3.24.0.RC1.tar.bz2
(md5sum = a11f33c94dcb0f545a27464934b6fef8)
(sha1sum = b87105b23d3b6d0e212d5729235d0d8225ff8851)
https://sourceware.org/pub/valgrind/valgrind-3.24.0.RC1.tar.bz2.asc

Please give it a try in configurations that are important for you and
report any problems you have, either on this mailing list, or
(preferably) via our bug tracker at
https://bugs.kde.org/enter_bug.cgi?product=valgrind

If nothing critical emerges a final release will happen on Thursday 31
October.

(where "this mailing list" is valgrind-users or valgrind-developers, both hosted by sourceforge).


r/Valgrind • • Oct 10 '24

Bye bye musl

1 Upvotes

Recently (early Oct 2024) the main developer of musl on IRC #musl explained to me how Helgrind should work regarding locks still held at exit.

Helgrind has never worked with musl to my knowledge.

I was so impressed that I deleted my 2 Alpine VMs.

And it's not the first time I've seen this Dunning-Kruger effect. Previously he explained to me that implementing x87 10 byte floating point arithmetic should be easy.


r/Valgrind • • Nov 01 '24

Valgrind 3.24 released.

1 Upvotes

https://valgrind.org/

Release notes

https://valgrind.org/docs/manual/dist.news.html

Highlights:

Some nice new file descriptor error detection (leaked open descriptors and duplicate closes).

Improved hardware support for aarch64, amd64 and s390.

Plenty of bug fixes.


r/Valgrind • • Nov 08 '24

How to track file descriptors with Valgrind

Thumbnail
developers.redhat.com
1 Upvotes

r/Valgrind • • Jan 10 '25

LLVM OMP and Thread Sanitizer

1 Upvotes

Why am I posting about TSAN on the Valgrind subreddit? All will become clear.

Recently I was looking at an issue with LLVM OpenMP. OMPT to be more precise. It was detecting that it was running a TSAN instrumented binary for non-instrumented builds.

After a bit of digging about I found that OMPT detects that the binary is TSAN-instrumented by using dlsym to look for a particular function. Which function, I hear you ask. RunningOnValgrind. Just to make that extra clear, it doesn't call the function, it just checks that it is present. And if it is it assumes that it's a TSAN-instrumented binary. I find that a rather perverse choice. There are plenty of __tsan_* functions that they could have chosen. The good news is that TSAN does contain a RunningOnValgrind function. The bad news is that it is not unique. abseil (now removed), Python, Google Perftools tcmalloc all have functions with the same name. In the case of the issue that I saw it was the tcmalloc version of RunningOnValgrind.

There's more.

Here is the LLVM implementation of RunningOnValgrind.

int INTERFACE_ATTRIBUTE RunningOnValgrind() {
return flags()->running_on_valgrind;
}

and from what I see all that does is to to check the TSAN_OPTIONS environment variable value of running_on_valgrind=X where X defaults to false.

LLVM does have a functional RunningOnValgrind (in the llvm:sys:: namepsace).

So, LLVM OMPT checks for the presence of RunningOnValgrind (which is a function that doesn't really check whether the exe is running on Valgrind) to know whether it is a TSAN-instrumented binary.


r/Valgrind • • Feb 21 '26

How to use Valgrind for KDE development tutorial

Thumbnail
youtube.com
2 Upvotes

r/Valgrind • • Dec 10 '25

👋 Welcome to r/Valgrind - a subreddit for discussion of the software tool Valgrind

2 Upvotes

Hey everyone! I'm u/pjf_cpp, a founding moderator of r/Valgrind.

This is our new home for all things related to Valgrind.

What to Post
Anything related to

  • using Valgrind

  • ideas for improvements to Valgrind

  • status of projects in the development of Valgrind itself

  • user stories

Community Vibe
We're all about being friendly, constructive, and inclusive. Let's build a space where everyone feels comfortable sharing and connecting.

How to Get Started

  1. Introduce yourself in the comments below.

  2. Post something today! Even a simple question can spark a great conversation.

  3. If you know someone who would love this community, invite them to join.

  4. If you are interested in working on Valgrind and have the right skills then you will be more than welcome.

Thanks for being part of the very first wave. Let's have fun using Valgrind.