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;
}
#Why is this code not leaking memory?
193 messages · Page 1 of 1 (latest)
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.
when I ran valgrind, it didn't give me any value that would say that it's leaking
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
-gfor gcc/clang and-Zifor msvc.
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.
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"
Does valgrind only consider what happens within main?
No, it tracks and considers the entire program
I mean, I consider that part of main.
I mean does it disregard what happens before and after main, like C runtime stuff
what is godbolt
can someone just come to a call?
it'd be better it's too hard to explain this way
Why should it be?
because the internal pointer inside Distance was never disallocated
assuming that the destructor of DIstance is like this : ~Distance(){}
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.
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
A pointer that is smart enough to automatically deallocate the memory. std::shared_ptr and std::unique_ptr etc.
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*
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.
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
There is no leak
The leak doesn't happen until you delete Distance without freeing the pointer inside of it first
what
Ok
Try constraining Distance objects in a scope block small enough.
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
;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;
}
that's the outcome of valgrind for the first code shown
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).
__snape | 80ms | c++ | x86-64 gcc 14.2 | godbolt.org
Check this out.
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?
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
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
The programmer doesn't, but the program still has access to that memory
That's the difference
why would you ever do this
Once the program loses access to the memory, then it's considered a memory leak
that's an easy way to kill a program
if the dev can't access a data that he created
You're not supposed to, that's the point lmao
then it should be a direct leak
who cares whether the program can access it or not
it's not the point
Private class properties
and public methods that act on them
Is a very simple example
here we're talking about a pointer address
not encapsulation
encapsulation is a completely different thing
encapsulation is just complicated pointer access controls
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
That's the power of low level.
It totally is in my stance.
you're basically killing your memory that way
like if the compiler can't even catch it
Just don't do that. You have the choice.
Use smart pointers.
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
The production code would be smart enough to use automatic memory management tools.
imo if you're just smart about allocating and freeing memory, it's not even a big deal
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.
Are you doing some sort of online course?
It's inherited from C.
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
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.
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
std::ostream& operator<<(std::ostream& os, const Distance& distance){
return os << "Distance(" << distance._content << ")";
}
that's all I did
What does this have to do with memory leak?
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
Im sorry! What shows 0?
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
This won't show you the leak anyway.
yes I agree
I don't know what's wrong then
but it seems like there is nothing wrong in your opinion
Maybe try what AlphaOmegaProgrammer Suggested.
No not free it, you just have to destroy Distance objects before the program ends.
Can you show the code (changed) once again?
#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
;cpp << x; int *x = nullptr;
Program Output
0
__snape | 45ms | c++ | x86-64 gcc (trunk) | godbolt.org
it does a segmentation fault on that exact line
Yes it should break.
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
#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;
}```
;compile
Program Output
100
__snape | 45ms | c++ | x86-64 gcc 14.2 | godbolt.org
I don't really know how the valgrind works, but yes could be the reason.
Try omitting that line. As it doesn't do anything significant for the leak scene .
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
🎆
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 Has your question been resolved? If so, type !solved :)
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