#Why is this code not leaking memory?

193 messages · Page 1 of 1 (latest)

smoky magnet
#
int main(){
    Distance const d1 = Distance(new Distance_meters(1));
    Distance const d2 = Distance(new Distance_leagues(3));
    std::cout << std::boolalpha << d1 << " vs " << d2 << " => " << (d1 < d2) << " | " << (d1 == d2) << " | " << (d1 > d2) << std::endl;
    Distance const* d3 = nullptr;
    std::cout << d3;
    return 0;
} 
lunar flareBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

smoky magnet
#

when I ran valgrind, it didn't give me any value that would say that it's leaking

minor magnet
#

What if you use address sanitizer?

#

!asan

lunar flareBOT
# minor magnet !asan
Address Sanitizer

Memory errors in C and C++ are easy to make and they can be very hard to debug because they can manifest far from their source. Address sanitizer is a runtime checker that identifies memory errors at their source and makes debugging much simpler. Address sanitizer is available for gcc/clang on linux and msvc on windows. To use it simply pass -fsanitize=address to the compiler.

Note: Make sure to turn on debug symbols with -g for gcc/clang and -Zi for msvc.

ce Example

How to read sanitizer output

The first few lines tell you the problem, heap-use-after-free, due to performing a READ of size 4, at example.c line 7 (from the first line of the stack trace).

==1==ERROR: AddressSanitizer: heap-use-after-free on address ....
READ of size 4 at 0x602000000010 thread T0
    #0 0x40120f in main /app/example.c:7
    #1 0x7fda58629d8f  (...)
    #2 0x7fda58629e3f in __libc_start_main (...)
    #3 0x4010b4 in _start (...)

Additional information is also included such as where the allocation was performed and where the allocation was freed.

See Also
  • Other sanitizers exist and can be similarly helpful, including ubsan, threadsan, and memorysan.
neon scarab
#

Memory isn't considered "lost" until the pointer to that memory is lost. In this case, all of the memory is still accessible at program exit, so none of the memory is considered "lost"

minor magnet
#

Does valgrind only consider what happens within main?

neon scarab
minor magnet
#

I mean, I consider that part of main.
I mean does it disregard what happens before and after main, like C runtime stuff

neon scarab
#

Oh, I believe so yes

#

I'm not sure though, I don't know much about C++

smoky magnet
#

what is godbolt

#

can someone just come to a call?

#

it'd be better it's too hard to explain this way

smoky magnet
#

because the internal pointer inside Distance was never disallocated

#

assuming that the destructor of DIstance is like this : ~Distance(){}

plucky frigate
#

Well it could be a smart pointer.

#

In that case a delete statement isn't required in destructor.

#

If you can see the implementation then ignore this.

smoky magnet
#

what is a smart pointer

#

my class distance has a pointer as a param

#

means I have to disalocate it

#

either in my destructor or manually

#

else it just remains

#

but valgrind returns 0 leaks

plucky frigate
smoky magnet
#

which is so weird to me

#

I didn't create those

#

I created it this way

#
Distance(const Distance_core* content) : _content(content) {}
#

where _content is a const Distance_core*

plucky frigate
# smoky magnet but valgrind returns 0 leaks

Well your program is short, at the point it can detect the leak it already terminates, the leak is supposed to happen after the destruction of Distance objects and that happens when the program is exitting.

smoky magnet
#

but it's homework

#

and the professor says it has to leak

#

that's not normal

#

I have a test that I'm running

#

and when I run that test ( in his code it has to leak )

#

in mine it doesn't

neon scarab
#

There is no leak

#

The leak doesn't happen until you delete Distance without freeing the pointer inside of it first

smoky magnet
#

what

neon scarab
#

Ok

plucky frigate
#

Try constraining Distance objects in a scope block small enough.

smoky magnet
#

I mean it's in a main

#

it's already such a small code

#

look at this

kindred owlBOT
#
Critical error:

You are sending requests too fast!

smoky magnet
#

take a look ```
==3139590== Memcheck, a memory error detector
==3139590== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==3139590== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==3139590== Command: ./programme
==3139590==
A distance of 1 meters was just created
A distance of 3 leagues was just created
1 meters vs 3 leagues => true | false | false
==3139590== Invalid read of size 8
==3139590== at 0x10AF36: operator<<(std::ostream&, Distance const*) (inheritance.cpp:94)
==3139590== by 0x10A385: main (memory_1.cpp:8)
==3139590== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==3139590==
==3139590==
==3139590== Process terminating with default action of signal 11 (SIGSEGV)
==3139590== Access not within mapped region at address 0x0
==3139590== at 0x10AF36: operator<<(std::ostream&, Distance const*) (inheritance.cpp:94)
==3139590== by 0x10A385: main (memory_1.cpp:8)
==3139590== If you believe this happened as a result of a stack
==3139590== overflow in your program's main thread (unlikely but
==3139590== possible), you can try to increase the size of the
==3139590== main thread stack using the --main-stacksize= flag.
==3139590== The main thread stack size used in this run was 8388608.
==3139590==
==3139590== HEAP SUMMARY:
==3139590== in use at exit: 73,776 bytes in 6 blocks
==3139590== total heap usage: 6 allocs, 0 frees, 73,776 bytes allocated
==3139590==
==3139590== LEAK SUMMARY:
==3139590== definitely lost: 0 bytes in 0 blocks
==3139590== indirectly lost: 0 bytes in 0 blocks
==3139590== possibly lost: 0 bytes in 0 blocks
==3139590== still reachable: 73,776 bytes in 6 blocks
==3139590== suppressed: 0 bytes in 0 blocks
==3139590== Reachable blocks (those to which a pointer was found) are not shown.
==3139590== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==3139590==
==3139590== For lists of detected and suppressed errors, rerun with: -s

plucky frigate
#

;compile -fsanitize=address

#include <random>
#include <iostream>
#include <thread>

struct Distance {
  Distance(int *const p) : pobj(p) {}

  int *const pobj = nullptr;
};

int main(){
    Distance const d1 = Distance(new int[10000]);
    Distance const d2 = Distance(new int);
    // std::cout << std::boolalpha << d1 << " vs " << d2 << " => " << (d1 < d2) << " | " << (d1 == d2) << " | " << (d1 > d2) << std::endl;
    Distance const* d3 = nullptr;
    std::cout << d3;
    return 0;
} 
smoky magnet
#

that's the outcome of valgrind for the first code shown

kindred owlBOT
#
Compiler Output
=================================================================
==1==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 40000 byte(s) in 1 object(s) allocated from:
    #0 0x7e4e586c1458 in operator new[](unsigned long) (/opt/compiler-explorer/gcc-14.2.0/lib64/libasan.so.8+0xfd458) (BuildId: e522418529ce977df366519db3d02a8fbdfe4494)
    #1 0x401229 in main /app/example.cpp:12
    #2 0x7e4e58029d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)

Direct leak of 4 byte(s) in 1 object(s) allocated from:
    #0 0x7e4e586c12f8 in operator new(unsigned long) (/opt/compiler-explorer/gcc-14.2.0/lib64/libasan.so.8+0xfd2f8) (BuildId: e522418529ce977df366519db3d02a8fbdfe4494)
    #1 0x401245 in main /app/example.cpp:13
    #2 0x7e4e58029d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)

SUMMARY: AddressSanitizer: 40004 byte(s) leaked in 2 allocation(s).
smoky magnet
#

I just redefined the operators

#

that's about it

plucky frigate
smoky magnet
#
bool operator ==(Distance const& d1, Distance const& d2){

    return d1._content->get_value() == d2._content->get_value();
}

bool operator !=(Distance const& d1, Distance const& d2){

    return d1._content->get_value() != d2._content->get_value();
}

bool operator >=(Distance const& d1, Distance const& d2){

    return d1._content->get_value() >= d2._content->get_value();
}

bool operator <=(Distance const& d1, Distance const& d2){

    return d1._content->get_value() <= d2._content->get_value();
}

bool operator >(Distance const& d1, Distance const& d2){
    
    return d1._content->get_value() > d2._content->get_value();
}

bool operator <(Distance const& d1, Distance const& d2){

    return d1._content->get_value() < d2._content->get_value();
}
#

it leaked 5k

#

but why does mine not leak?

plucky frigate
#

So total of 10k

smoky magnet
#

I get it

#

I don't understand while yours leaks

#

while mine doesn't

plucky frigate
#

What do you do to detect it?

#

I used address sanitizer.

neon scarab
#

I'm too skill issued to demonstrate this in C++, so I'll give a very simple C example:

int main(int argc, char** argv){
  char *buffer = malloc(1000);

  return 0;
}

This has no memory leak, because the 1000 bytes that were allocated to buffer are still accessible when the end of main is reached. However:

int main(int argc, char** argv){
  char *buffer = malloc(1000);

  buffer = NULL;

  return 0;
}

Now this has a memory leak, because the memory stored in buffer are no longer accessible when the end of main is reached.

The reason valgrind shows nothing for you is because the property inside of your Distance class is still accessible when the program exits

smoky magnet
#

how can I access it

#

I don't have the pointer to access it

#

I lost access to that pointer

#

I don't have it's address

neon scarab
#

That's the difference

smoky magnet
#

why would you ever do this

neon scarab
#

Once the program loses access to the memory, then it's considered a memory leak

smoky magnet
#

that's an easy way to kill a program

#

if the dev can't access a data that he created

neon scarab
smoky magnet
#

then it should be a direct leak

#

who cares whether the program can access it or not

#

it's not the point

neon scarab
#

and public methods that act on them

#

Is a very simple example

smoky magnet
#

here we're talking about a pointer address

#

not encapsulation

#

encapsulation is a completely different thing

neon scarab
smoky magnet
#

it's under the hood

#

I'm talking about what's visible

neon scarab
#

The point is that there are many times where the program can still mess with pointers that the programmer doesn't have direct access to

plucky frigate
smoky magnet
#

power?

#

you leave some data of a program to be unused?

#

That's power?

plucky frigate
#

It totally is in my stance.

smoky magnet
#

you're basically killing your memory that way

#

like if the compiler can't even catch it

plucky frigate
smoky magnet
#

how are you supposed to know about it

#

I'm not talking about my case

plucky frigate
smoky magnet
#

I'm talking about production code where you'd have regressions and stuff like that

#

It'd end up faulting today or tommorow

#

and debug tools wouldn't even help you out

#

Because at the end of the day

#

you and I are humans

#

we make mistakes

#

even if you're a 10x dev

plucky frigate
#

The production code would be smart enough to use automatic memory management tools.

smoky magnet
#

well that quite answered my question

#

but yet it didn't

neon scarab
#

imo if you're just smart about allocating and freeing memory, it's not even a big deal

smoky magnet
#

bro said it has to leak memory

#

I'm supposed to say no it doesn't hahaha

plucky frigate
#

It's a primitive construct, memory allocation returns the pointer to the allocated region, your responsibility is to keep track of it, you lose the address/pointer you leak the memory.

neon scarab
plucky frigate
#

It's inherited from C.

smoky magnet
#

it's an exercise given by my professor

#

so I don't get it

#

it's just nonsense

#

he says it has to give me some lines that I'm not getting

#

my implementation doesn't look wrong either

#

I just redefined the operators

#
bool operator ==(Distance const& d1, Distance const& d2){

    return d1._content->get_value() == d2._content->get_value();
}

bool operator !=(Distance const& d1, Distance const& d2){

    return d1._content->get_value() != d2._content->get_value();
}

bool operator >=(Distance const& d1, Distance const& d2){

    return d1._content->get_value() >= d2._content->get_value();
}

bool operator <=(Distance const& d1, Distance const& d2){

    return d1._content->get_value() <= d2._content->get_value();
}

bool operator >(Distance const& d1, Distance const& d2){
    
    return d1._content->get_value() > d2._content->get_value();
}

bool operator <(Distance const& d1, Distance const& d2){

    return d1._content->get_value() < d2._content->get_value();
}
#

but except that I haven't done much

#

and the << operator

plucky frigate
#

The reason it exists is that the C++ is based upon C, so it automatically gets stuff from C, the C++ alternative to the resource management approach is laid bare in the form of smart pointers and general RAII.

smoky magnet
#

so what my professor says in that exercise is wrong?

#

it's not going to leak?.

neon scarab
#

It's considered a leak because freeing Distance doesn't free the pointer inside of Distance, but you're not actually going to see that using a tool like valgrind until you actually free Distance

#

valgrind isn't magical, it can only observe leaks that happen

smoky magnet
#
std::ostream& operator<<(std::ostream& os, const Distance& distance){
    
    return os << "Distance(" << distance._content << ")";
}
#

that's all I did

plucky frigate
#

What does this have to do with memory leak?

smoky magnet
#

I don't know I want to know the reason why it always shows a 0

#

while the guy says it has to leak about 80 bytes

plucky frigate
#

Im sorry! What shows 0?

smoky magnet
#

He basically gave a test file

#

where valgrind

#

shows this 6 times:
16 bytes in 1 blocks are definitely lost in

#

well I guess there is something wrong in there

#

I'll see

#

thank you

plucky frigate
smoky magnet
#

yes I agree

#

I don't know what's wrong then

#

but it seems like there is nothing wrong in your opinion

plucky frigate
#

Maybe try what AlphaOmegaProgrammer Suggested.

smoky magnet
#

I tried freeing it

#

as he said

plucky frigate
#

No not free it, you just have to destroy Distance objects before the program ends.

smoky magnet
#

yes that's what I did

#

added delete d1 and delete d2 in the end

plucky frigate
#

Can you show the code (changed) once again?

smoky magnet
#
#include "inheritance.hpp"
#include <iostream>
int main(){
    Distance const* d1 = new Distance(new Distance_meters(1));
    Distance const* d2 = new Distance(new Distance_leagues(3));
    std::cout << std::boolalpha << d1 << " vs " << d2 << " => " << (d1 < d2) << " | " << (d1 == d2) << " | " << (d1 > d2) << std::endl;
    Distance const* d3 = nullptr;
    delete d1;
    delete d2;
    std::cout << d3;
    
    return 0;
} 
#

I need to say something though

#

the std::cout << d3

#

is attempting to show d3->_content

#

but d3 is nullptr

#

so I'm trying to access _content with a nullpointer

#

so it breaks there

plucky frigate
#

;cpp << x; int *x = nullptr;

kindred owlBOT
#
Program Output
0
smoky magnet
#

it does a segmentation fault on that exact line

plucky frigate
smoky magnet
#

The thing is if it breaks there

#

then I'm never leaving the function normally

#

so the allocated space should be freeed

#

if it doesn't then it's horrible

#

it's like an exception in some sort of way

#

everything stops

plucky frigate
#
#include <iostream>

struct Dummy {
  int x = 100;
};

std::ostream& operator<<(std::ostream &os, const Dummy*const d) {
  return os << d->x;
};

int main() {
  Dummy * pd = new Dummy;
  std::cout << pd;
}```
kindred owlBOT
#
Program Output
100
plucky frigate
#

Try omitting that line. As it doesn't do anything significant for the leak scene .

smoky magnet
#

it leaks

#

but there is some other error that should be shown ( it's displayed in the test ) but if I remove that line it doesn't show it anymore

plucky frigate
#

🎆

smoky magnet
#

Invalid read of size 8

#

it's like a puzzle

plucky frigate
#

That's probably the line that tries to read/dereference the pointer to Distance in the output/insertion operator.

#

I've gotta go.

#

Good bye!

smoky magnet
#

yes

#

thank you

#

bye

lunar flareBOT
#

@smoky magnet Has your question been resolved? If so, type !solved :)

smoky magnet
#

Yes and no

#

!solved

lunar flareBOT
#

Thank you and let us know if you have any more questions!

This thread is now set to auto-hide after an hour of inactivity