tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Leak Sanitizer - how to suppress leaks



On 12.09.2019 10:09, Robert Elz wrote:
> The right change to make however is to teach the santitsers (all of them)
> that exiting (via exit() or a return from main()) frees everything,

This proposal is practically equivalent of disabling leak detection at
all and removes the whole purpose.

Leak detection works simply by scanning memory (TLS, stacks, heap) for
pointers to allocations. If there is no longer a reference, than there
is a leak.

I have not investigated where are the sh(1) leaks, but the pointers are
still accessible in memory. There are few tests failing in regression
test-suite and they related to pointers that are on the stack. There is
apparently a bug in calculating the range of used/valid stack region
somewhere or something that has this red-herring effect. (I would like
to see it fixed, but I am supposed to do other things now and cannot
focus on it.)

On 12.09.2019 10:55, Jason Thorpe wrote:>
>> On Sep 12, 2019, at 11:09 AM, Robert Elz <kre%munnari.OZ.AU@localhost> wrote:
>>
>> To me it seems apparent that the sanatiser is detecting the local
variable
>> in main() go out of scope when main() returns, and so the value it
contains
>> (the pointer to the allocated memory) is lost, and so it is
determined that
>> there is a leak.   For any other function that would often be true,
but for
>> main() it never is.
>
> It seems obvious that the sanitizer should special-case main().
>
> -- thorpej
>

In sanitizers we cannot overload or do anything special with main()
(such as replace it with our own copy). If this would be the case, it
would be simpler to perform some operations in other sanitizers.

main() is the same entity as any regular fun(). Unless we decorate it
with some attributes in .c code, it is not distinguishable.


On 12.09.2019 07:39, Simon Burge wrote:> for the free-just-before-exit
cases?

Leak detection is performed just before the exit.

Technically it is performed from atexit(3) handler that is expected to
be the last one to be executed.

We need to perform this phase in that moment as we need to fire other
atexit handlers, destructors etc.

main() is not really privileged here.

At least with LSan there is an option to perform the end-of-process
check on demand with __lsan_do_leak_check(), it will disable the
atexit(3) handler later on. But it is not much different to adding
workarounds for 1 type of leak detecting software.

On 12.09.2019 10:09, Robert Elz wrote:> If this is what is happening, it
would seem that a relatively cost free
> fix, instead of calling free()

Globals are treated specially in sanitizers as sanitizers generate
constructors and destructors to keep the track of them.

LSan on NetBSD is still distanced from being as good as the Linux
equivalent so it's not a perfect example of presenting how LSan
behaves., I wouldn't assume that globals can store freely pointers. Even
if this is the case today, it would be fixed in future.


On 12.09.2019 10:09, Robert Elz wrote:>   | There is a cost of calling a
dummy function _suppress_leak(), but it is
>   | probably negligible.
>
> No, it isn't.   The way you have described it, that function needs to be
> called for every block of allocated memory that has been allocated, and is
> never going to be freed.   That means either calling this function
immediately
> after all (or much) memory is allocated, even if it turns out that
memory is
> later freed, as often the code does not know what allocations will be
released
> and which will still be active when the program terminates.   Or every
time
> the program is about to exit, it needs to traverse all of its data
structures
> calling this function on all memory that had perviously been allocated.
> Potentially thousands of these dummy function calls.

I have benchmarked in the past that we execute for true(1) or similar
applications at least 1 million instructions on CPU.


$ ./singlestepper true
Total count: 1639915

$ ./singlestepper echo

Total count: 1039124

Calling one 1 dummy function in libc in comparison to that is negligible.

We are talking here about simple programs that are expected to get some
measurable optimization by skipping free(3) calls. Such as sh(1) or ps(1).

In all other cases I consider this style of programming as buggy.

If there are thousands of leaked memory objects than it is not just
simple optimization, but really wrong style of programming. One example
of that is ATF, it randomly picks one set of pointers to free before
exit, and skips others leaking the memory. It is bug.

As I have stated originally, we could remove free(3) from almost every
basesystem program and not many would notice. There is even a C compiler
that performs only allocations and never frees the memory. It is still a
correct UNIX application, regardless of taking like 2GB for building a
hello world application.

Attachment: signature.asc
Description: OpenPGP digital signature



Home | Main Index | Thread Index | Old Index