New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: BUG: Fix pointer type in memory allocation #3459
WIP: BUG: Fix pointer type in memory allocation #3459
Conversation
Fix pointer type in memory allocation call.
I'd be grateful if anyone could run Valgrind on this branch before making further changes. I want to know if this fixes at least some of the issues. |
case itk::IOComponentEnum::INT: | ||
buffer = new unsigned int[bufferSize]; | ||
buffer = new int[bufferSize]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a proper fix to me. In this particular case (IOComponentEnum::INT
), int
must have been intended, instead of unsigned int
. However, I don't expect any observable behavior change. In C++, a pointer to unsigned int
may be converted to a void pointer, and then casted to and "interpreted" as a pointer to signed int
, without runtime errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I look from time to time at Valgrind builds. IMHO, the whole approach, that AllocateBuffer
and void**
, should be reviewed. Exactly after #3403 the amount of Valgrind defects went from 1 to 33, they are all from mesh tests and about the allocation helper.
The errors are like this:
FMM ==16981== Mismatched free() / delete / delete []
==16981== at 0x483CFBF: operator delete(void*) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16981== by 0x1FF10D: itkOBJMeshIOTest(int, char**) (itkOBJMeshIOTest.cxx:183)
==16981== by 0x12ED77: main (ITKIOMeshOBJTestDriver.cxx:142)
==16981== Address 0x89e4ab0 is 0 bytes inside a block of size 400,000 alloc'd
==16981== at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16981== by 0x1FB27A: AllocateBuffer(void**, itk::CommonEnums::IOComponent, unsigned long) (itkMeshIOTestHelper.h:416)
==16981== by 0x1FDB56: itkOBJMeshIOTest(int, char**) (itkOBJMeshIOTest.cxx:106)
==16981== by 0x12ED77: main (ITKIOMeshOBJTestDriver.cxx:142)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed typo in links to builds.
Shortly, current implementation (after #3403) does following: void my_alloc(void ** p)
{
void * i = nullptr;
i = new int[1000];
*p = i;
}
int main(int, char**)
{
void * p = nullptr;
my_alloc(&p);
::operator delete(p);
return 0;
}
It is wrong, BTW that unusual I don't have time to dig ITK mesh classes, i don't use them, just some ideas (assumed void my_alloc(void ** p)
{
int * i = new int[1000];
p[0] = static_cast<void*>(i);
}
int main(int, char**)
{
void * p[1];
my_alloc(p);
int * i = static_cast<int*>(p[0]);
delete[] i;
return 0;
} will not cause errors and warnings, there are many variants, of course, ( In fact, i don't really know much about the mesh tests and what is the best solution. |
Thanks @issakomi Your comments do make thinks clearer! So the problem is that the buffers should have been deleted by I think this could be solved by RAII -- let the buffers take case of deleting their own pointers automatically, in the appropriate way. However, it isn't entirely trivial, I must admit 🤔 I think something like this could solve the Valgrid defects: master...N-Dekker:Add-Buffer-to-MeshIOTestHelper The added |
Another approach could be to have AllocateBuffer return an https://github.com/N-Dekker/ITK/tree/AllocateBuffer-return-shared_ptr-void What do you think? |
Let AllocateBuffer (from MeshIOTestHelper) return a `std::shared_ptr<void>`, instead of producing a void pointer, to ensure that it is deleted correctly, automatically. Aims to fix Valgrind errors, saying: > Mismatched free() / delete / delete [] As reported and discussed by Jon Haitz Legarreta Gorroño and Mihail Isakov at pull request InsightSoftwareConsortium#3459
Yes, i got this version close to the current with void my_alloc(void ** p)
{
int * i = new int[1000];
*p = static_cast<void*>(i);
}
int main(int, char**)
{
void * p;
my_alloc(&p);
::operator delete[](p);
return 0;
} Where is no Valgrind error, but i am still not sure, simple |
Let AllocateBuffer (from MeshIOTestHelper) return a `std::shared_ptr<void>`, instead of producing a void pointer, to ensure that it is deleted correctly, automatically. Aims to fix Valgrind errors, saying: > Mismatched free() / delete / delete [] As reported and discussed by Jon Haitz Legarreta Gorroño and Mihail Isakov at pull request InsightSoftwareConsortium#3459
Thanks both @issakomi and @N-Dekker 💯 for your time and insights into the problem, and for proposing possible solutions.
I had tried this in PR #3403 prior to switching to
As a follow up to the commit in the current branch, I had a new commit ready to go doing this: in every test file, a
Maybe that would have worked/removed the memory leaks, but I wanted to avoid it, as it involves repeating almost the exact same code for every buffer, in each and every test affected by the issue. Unfortunately, I do not have a better proposal over the ones proposed in #3459 (comment) or in PR #3460. I am not familiar with RAII, but the solution looks very elegant. If we are satisfied with PR #3460 / if it does not incur memory leaks, I would close this in its favor. Again, thanks both of you ! |
Thanks @jhlegarreta Just to clarify the RAII idiom. It's the very common C++ technique to let destructors of classes take care of deallocation of memory and other resources. Instead of having to call free and delete functions manually, at the end of your functions. You're already using RAII on many places, even if you're not familiar with the term. For example, when you declare ITK/Modules/IO/MeshGifti/test/itkGiftiMeshIOTest.cxx Lines 48 to 52 in 0fcfaf1
Both On the other hand, when you have those operator HTH, Niels |
Let AllocateBuffer (from MeshIOTestHelper) return a `std::shared_ptr<void>`, instead of producing a void pointer, to ensure that it is deleted correctly, automatically. Aims to fix Valgrind errors, saying: > Mismatched free() / delete / delete [] As reported and discussed by Jon Haitz Legarreta Gorroño and Mihail Isakov at pull request #3459
@issakomi @jhlegarreta Can you possibly confirm that Valgrind is happy now, with git master branch commit db8d797 I do expect so, but I just want to be sure 😃 |
Minimal local test runs fine, without compiler warnings (Linux, gcc 8.3.0) or Valgrind defects: #include <memory>
template <typename T>
std::shared_ptr<void>
MakeSharedArray(const std::size_t bufferSize)
{
return std::shared_ptr<void>(new T[bufferSize], std::default_delete<T[]>());
}
int main(int,char**)
{
const std::shared_ptr<void> p = MakeSharedArray<double>(100000);
return 0;
}
|
@issakomi Cool, I'm glad to see that |
Superseded by #3460. |
@N-Dekker Looks good, no more https://open.cdash.org/viewDynamicAnalysis.php?buildid=7966303 |
Fix pointer type in memory allocation call.
PR Checklist