vermaseren / form

The FORM project for symbolic manipulation of very big expressions
GNU General Public License v3.0
985 stars 118 forks source link

Valgrind reports memory leak due to FactArg #507

Open jodavies opened 1 month ago

jodavies commented 1 month ago

In the following example, valgrind reports a leak:

64 bytes in 1 blocks are definitely lost in loss record 52 of 161
   at 0x4849013: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x1CA6A2: allocate (new_allocator.h:127)
   by 0x1CA6A2: allocate (alloc_traits.h:464)
   by 0x1CA6A2: _M_allocate (stl_vector.h:346)
   by 0x1CA6A2: _M_create_storage (stl_vector.h:361)
   by 0x1CA6A2: _Vector_base (stl_vector.h:305)
   by 0x1CA6A2: vector (stl_vector.h:524)
   by 0x1CA6A2: polyfact::Berlekamp_find_factors(poly const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&) (polyfact.cc:1270)
   by 0x1CC566: polyfact::factorize_squarefree(poly const&, std::vector<int, std::allocator<int> > const&) (polyfact.cc:1485)
   by 0x1CE1F0: polyfact::factorize(poly const&) (polyfact.cc:1673)
   by 0x1DBC73: poly_factorize(int*, int*, bool, bool) (polywrap.cc:946)
   by 0x1DC1E8: poly_factorize_argument (polywrap.cc:1062)
   by 0x117E11: ArgFactorize (argument.c:2255)
   by 0x11B7A7: execarg (argument.c:1121)
   by 0x1F4AA9: Generator (proces.c:3616)
   by 0x1F5946: Generator (proces.c:4048)
   by 0x1F5DAA: Generator (proces.c:4216)
   by 0x1F5946: Generator (proces.c:4048)

This code is cut down from a larger test (#505). At this point it seems if I comment anything out, the error disappears:

#-

Off Statistics;

AutoDeclare Symbol n,m;
Symbol ep;
CFunction den,num;
Symbol coefftx,coeffty;

Local test4 = + den(ep)*den(ep^3*m3 + ep^2*m2 + ep*m1 + m0)*num(ep)*num(ep^3*n3 + ep^2*n2 + ep*n1 + n0);
Local test5 = + den(ep^3*m3 + ep^2*m2 + ep*m1 + m0)*num(ep^6*n6 + ep^5*n5 + ep^4*n4 + ep^3*n3 + ep^2*n2 + ep*n1 + n0);

FactArg num;
FactArg den;

SplitArg ((ep)) num;
Identify num(ep) = ep;
Transform num addargs(2,last);
FactArg num;

Print +s;
.end
jodavies commented 1 month ago

Here is a smaller example:

#-

Off Statistics;

Symbol n6,...,n1;
*Symbol n1,...,n6;
Symbol ep;
CFunction num;

Local test4 =
    + num(ep*n1 + ep^2*n2 + ep^3*n3 + ep^4*n4 + ep^5*n5 + ep^6*n6)
   ;

FactArg num;

Print +s;
.end

It is a bit delicate. Changing the decl order of n1,...,n6 removes the leak. Deleting the ep^5 term results in a slightly larger leak. Removing other terms removes the leak.

As far as I can see, none of the allocations here are dynamic, I am not sure where a leak can come form.

jodavies commented 1 month ago

I can't make any sense of this one. I see it with gcc 11.4 and 12.3, but not with clang 14.0.

I can't make it leak more than 96 bytes, even if looping,

FactArg num;
Transform num mulargs(1,last);
.sort

processing more than one expression, or having more than one function per term.

At least in the context of #505 , I think I would just skip that test when running under valgrind...

tueda commented 1 month ago

Interestingly, I get the Valgrind "definitely lost" error with gcc 12.3.0 and 13.2.0, but it works cleanly with gcc 14.1.0...

A more minimized test:

CF f;
S a,b,x;
L F = f(a*x^3 + 1) * f(x^2 + a*x + 1) * f(a*x^3 + b*x^2 + a*x + 1);
factarg f;
.end
tueda commented 1 month ago

Tests on Docker for reproducibility:

docker run -it --rm ubuntu:24.04
GCC_VERSION=9
apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends automake ca-certificates git g++-$GCC_VERSION libgmp-dev libmpfr-dev make valgrind zlib1g-dev
git clone https://github.com/vermaseren/form form-gcc-$GCC_VERSION
cd form-gcc-$GCC_VERSION
git checkout 74735f57a7351e5c790648f2332d06c164d701d0
autoreconf -if
CC=gcc-$GCC_VERSION CXX=g++-$GCC_VERSION ./configure --enable-debug
make -C sources -j $(nproc) vorm
git clone https://gist.github.com/4cfd625d3e5e1336f6c6fa02cc33aed7.git tests
valgrind sources/vorm tests/507-1.frm
valgrind sources/vorm tests/507-2.frm
valgrind sources/vorm tests/507-3.frm
valgrind sources/vorm tests/507-4.frm
valgrind sources/vorm tests/507-5.frm

With GCC 9 and 10, I got the memory leak: definitely lost: 64 bytes in 1 blocks, but it cleanly works with GCC 11, 12, 13 and 14 .

This seems to be an issue with gcc, glibc, and/or Valgrind.