Open Hanseltu opened 2 days ago
I don't think I see the leak at the code.
Ap_sort
does make an allocation which the VM is not aware of (note: can it be a userdata
object?), but it's inside try/catch, and it's freed at the catch part, and the pointer variable is appropriately volatile
. So it's not immediately obvious to me why it would leak.
Which version of mujs are you testing? Can you try with current master if you were testing with an older version? (I don't have the bandwidth to look into it myself, so these are just thoughts)
The leak happens because the callback throws an exception, which longjmps out of the qsort function.
On GNU libc, qsort is implemented as a mergesort with temporary storage allocated with malloc. When the callback jumps out with an exception, libc leaks that storage.
We can replace the use of system qsort with our own implementation of an in-place sorting algorithm, such as heapsort (which is approx 2x slower than gnu libc's mergesort on a large arrays).
libc leaks that storage.
Interesting.
Long while ago I experimented with different sorts.
I think this is a minimal implementation of mujs heap sort, and as far as I recall it was on par with glibc - not slower than x1.3 or some such, but there could be classes of input which I didn't test. (I also have similar code with other "base" sort functions, like quicksort and other types, some surprisingly tiny).
It has two siftdown
functions, and I don't recall which is better/faster (I'm pretty sure both work, and I have few more which I didn't copy here, some faster than others, and other variables).
Hopefully it's complete, but I extracted it manually from an old large file with lots of experiments, so hopefully I got the right parts. Maybe it can be reused. I didn't try to compile it now:
I found some of our old sorting experiments on various branches (including your heapsort, and an in-place quicksort implementation). I'll see if I can revive one of those to fix this issue.
Added to the code above a missing tiny intermediate function (copied from the same old experiments file):
static void sort_r(void *arr, size_t n, size_t size, cmp_ft cmp, void *J)
{
// size assumed of js_Value, cmp hardcoded
if (n > 1)
js_heapsort(J, arr, n);
}
It has two
siftdown
functions, and I don't recall which is better/faster (I'm pretty sure both work
I think I remember now. The xsiftdown
function is more generic and uses only swaps. and it doesn't know the size of an element (so it can't keep a copy of an element outside the array), while the siftdown
function is (more?) mujs-specific, and uses js_Value
to hold an element outside the array, and it can assign arrays elements directly from place to place, and therefore should be faster (and because of that, uses a very slightly different approach, which typically results in less iterations and much less assignments. both are "bottom up" sift-down).
It doesn't even need to pause the GC or use try/catch, no allocations outside of the VM, because it uses the flat array mode.
Hi,
The following test input (
input.js
) causes the possible memory leaks.Compilation command: add
-fsanitize=address
intoCFLGAS
inMakefile
. Compiler version:gcc-7.5.0
. System:ubuntu 18.04
.mujs
version:1.3.5
.Thanks.