You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
tree.diffIndex: pointer being freed was not allocated #112
Has anyone run into this issue that seems to be happening in tree.diffIndex? It happens sporadically -- it seems to occur during garbage collection. My app crashes with:
node(16403,0x7fff77c61310) malloc:
*** error for object 0x100d05720: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
I am not sure how to get any more information beyond this. Tried searching for malloc_error_break to try to insert a breakpoint but I am not seeing it.
can you paste the backtrace? you can get this using gdb from the coredump or running your code in gdb. if you know what's causing it, if you sprinkle gc() throughout your code (using node --expose-gc) you might be able to get this to reproduce more reliably.
Got it. Thanks. Sorry for the delay, this was next to impossible to accomplish in Mavericks -- had to get an Ubuntu VM running and it took 5 seconds.
Here is the backtrace, let me know how if I can help. It only happens when there are changes in the working directory or in the index. If the diffList is empty, the segfault never occurs.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6c4acd3 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0 0x00007ffff6c4acd3 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ffff6c4b898 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00000000005970eb in node::Buffer::Replace(char*, unsigned long, void (*)(char*, void*), void*) ()
#3 0x0000000000597179 in node::Buffer::~Buffer() ()
#4 0x00000000005971e9 in node::Buffer::~Buffer() ()
#5 0x00000000005985f6 in node::ObjectWrap::WeakCallback(v8::Persistent<v8::Value>, void*) ()
#6 0x0000000000755fec in v8::internal::GlobalHandles::PostGarbageCollectionProcessing(v8::internal::GarbageCollector) ()
#7 0x0000000000771a68 in v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GCTracer*) ()
#8 0x0000000000771fd8 in v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollector, char const*, char const*) ()
#9 0x0000000000875d42 in v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, char const*) ()
#10 0x000018ffabb06214 in ?? ()
#11 0x000018ffabb060e1 in ?? ()
#12 0x00007fffffffa4f0 in ?? ()
#13 0x00007fffffffa548 in ?? ()
#14 0x000018ffabe6d6dd in ?? ()
#15 0x0000346482a5bc99 in ?? ()
#16 0x0000000300000000 in ?? ()
#17 0x00003e823bd87491 in ?? ()
#18 0x0000267fe4719da9 in ?? ()
#19 0x0000267fe4719da9 in ?? ()
#20 0x00003e823bdffea1 in ?? ()
#21 0x00003e823bdef199 in ?? ()
#22 0x00007fffffffa5a0 in ?? ()
#23 0x000018ffabb156ce in ?? ()
#24 0x0000267fe4719949 in ?? ()
#25 0x000008214232c321 in ?? ()
#26 0x0000267fe4719d71 in ?? ()
#27 0x0000267fe4719d91 in ?? ()
#28 0x0000267fe4719d91 in ?? ()
#29 0x0000000300000000 in ?? ()
#30 0x000018ffabb154c1 in ?? ()
#31 0x0000000700000000 in ?? ()
#32 0x00000ef93e7bd559 in ?? ()
#33 0x00007fffffffa5e8 in ?? ()
#34 0x000018ffabe6d555 in ?? ()
#35 0x0000267fe4719949 in ?? ()
Well, it's somewhat narrowed down in that it's in Buffer, but I'm not entirely sure where it's coming from. If we can narrow down what causes the problem, that would be easier.
For example, does just doing the diff lead the segfault? Or do you have to look at the patch? And if you look at the patch, what part of it?
In my diff function I am actually calling a couple different diffs and merging them together, then iterating the patches. I will set up a few different tests that hit different points of the code to try to narrow it down. But intuitively, I think you may be right -- the patches seem to be the common denominator.
You're right -- it's in the patches. When calling the diff functions, if I don't touch diffList.patches() then the segfault does not occur. Will look into this further.
Well, I have a test where all I am doing is diffList.patches().length and it is segfaulting. It looks to me the only thing that function does is produce an array of ConvenientPatch objects. So, ConvenientPatch constructor?
I went ahead and added that line "copy": "git_diff_delta_dup" to "cFunctionName": "git_diff_get_patch" and it appears to have fixed the problem. Any insight into what was going on?
Nodegit has C++ bindings to libgit2. Those bindings aren't hand-written, they're generated with a code generator that I wrote. The code-generator takes a config file (v0.18.0.json) that specifies how to generate the bindings. The single trickiest issue is mapping memory lifecycle issues across v8 -- a garbage collected runtime -- and libgit2, which requires manual memory management. In general, functions like git_diff_delta malloc objects and expect the caller to free them. By convention, that becomes a destructor on an object that is called when v8 garbage collects. This works fine, except in the small handful of cases where the caller is NOT responsible for freeing objects themselves; this usually happens when a method returns a nested field of a struct and that field is freed when the parent is freed (in this case the patch contains a delta; you're not supposed to free the delta: freeing the patch frees the delta). For these cases, the convention is to duplicate the object (e.g., using git_diff_delta_dup) so it can last longer than its parent object -- this is necessary if you start passing around the child field in javascript land but let the parent get garbage collected.
I get what seems to be the same or very similar bug to this on the latest version of nodegit (which includes the above mentioned fix, so I guess it's not the same bug, but the error message is the same and it is triggered during garbage collection). Backtrace is as follows:
Activity
nkallen commentedon Nov 15, 2013
can you paste the backtrace? you can get this using gdb from the coredump or running your code in gdb. if you know what's causing it, if you sprinkle
gc()throughout your code (usingnode --expose-gc) you might be able to get this to reproduce more reliably.kmctown commentedon Nov 16, 2013
Got it. Thanks. Sorry for the delay, this was next to impossible to accomplish in Mavericks -- had to get an Ubuntu VM running and it took 5 seconds.
Here is the backtrace, let me know how if I can help. It only happens when there are changes in the working directory or in the index. If the diffList is empty, the segfault never occurs.
Thanks
nkallen commentedon Nov 18, 2013
Well, it's somewhat narrowed down in that it's in Buffer, but I'm not entirely sure where it's coming from. If we can narrow down what causes the problem, that would be easier.
For example, does just doing the diff lead the segfault? Or do you have to look at the patch? And if you look at the patch, what part of it?
nkallen commentedon Nov 18, 2013
After some googling, this may depend on the version of node.js. Can you let me know which version you're using ?
kmctown commentedon Nov 18, 2013
Sure. I'm using v0.10.22.
In my diff function I am actually calling a couple different diffs and merging them together, then iterating the patches. I will set up a few different tests that hit different points of the code to try to narrow it down. But intuitively, I think you may be right -- the patches seem to be the common denominator.
kmctown commentedon Nov 18, 2013
You're right -- it's in the patches. When calling the diff functions, if I don't touch diffList.patches() then the segfault does not occur. Will look into this further.
nkallen commentedon Nov 18, 2013
please narrow it down to one function if possible. It might be easiest to
--expose-gcand call gc() in your code.kmctown commentedon Nov 18, 2013
Well, I have a test where all I am doing is
diffList.patches().lengthand it is segfaulting. It looks to me the only thing that function does is produce an array ofConvenientPatchobjects. So,ConvenientPatchconstructor?nkallen commentedon Nov 18, 2013
It's not the constructor, but calling
.patches()callsdiffList.patch(i)where0 < i < length. So presumably the bug is in thepatchmethod https://github.com/nodegit/nodegit/blob/master/src/diff_list.cc#L179I'm still unclear on what the actual bug is since this code doesn't have much to do with
Buffer. Can you double check the backtrace again?nkallen commentedon Nov 18, 2013
I have a theory. I'm going to assume the backtrace you pasted earlier is an unrelated issue.
Can you apply the following patch to your local checkout and rebuild the code with
npm run-script gen && npm install && npm test:kmctown commentedon Nov 18, 2013
I went ahead and added that line
"copy": "git_diff_delta_dup"to"cFunctionName": "git_diff_get_patch"and it appears to have fixed the problem. Any insight into what was going on?kmctown commentedon Nov 18, 2013
Thanks
nkallen commentedon Nov 18, 2013
Nodegit has C++ bindings to libgit2. Those bindings aren't hand-written, they're generated with a code generator that I wrote. The code-generator takes a config file (
v0.18.0.json) that specifies how to generate the bindings. The single trickiest issue is mapping memory lifecycle issues across v8 -- a garbage collected runtime -- and libgit2, which requires manual memory management. In general, functions likegit_diff_deltamalloc objects and expect the caller to free them. By convention, that becomes a destructor on an object that is called when v8 garbage collects. This works fine, except in the small handful of cases where the caller is NOT responsible for freeing objects themselves; this usually happens when a method returns a nested field of a struct and that field is freed when the parent is freed (in this case the patch contains a delta; you're not supposed to free the delta: freeing the patch frees the delta). For these cases, the convention is to duplicate the object (e.g., usinggit_diff_delta_dup) so it can last longer than its parent object -- this is necessary if you start passing around the child field in javascript land but let the parent get garbage collected.nkallen commentedon Nov 18, 2013
can you submit a pull request with this fix?
kmctown commentedon Nov 18, 2013
No problem.
kmctown commentedon Nov 19, 2013
Pull request is submitted #113
hugovincent commentedon May 1, 2014
I get what seems to be the same or very similar bug to this on the latest version of nodegit (which includes the above mentioned fix, so I guess it's not the same bug, but the error message is the same and it is triggered during garbage collection). Backtrace is as follows: