Hi Hackers,

I noticed a memory leak:
```
static void
libpqrcv_processTuples(PGresult *pgres, WalRcvExecResult *walres,
                                           const int nRetTypes, const Oid 
*retTypes)
{
        walres->tuplestore = tuplestore_begin_heap(true, false, work_mem);

        /* Create tuple descriptor corresponding to expected result. */
        walres->tupledesc = CreateTemplateTupleDesc(nRetTypes);
        for (coln = 0; coln < nRetTypes; coln++)
                TupleDescInitEntry(walres->tupledesc, (AttrNumber) coln + 1,
                                                   PQfname(pgres, coln), 
retTypes[coln], -1, 0);

        attinmeta = TupleDescGetAttInMetadata(walres->tupledesc); <== attinmeta 
is not free-ed

        /* No point in doing more here if there were no tuples returned. */
        if (PQntuples(pgres) == 0)
                return;
```

I understand that it is a common pattern where memory are free-ed automatically 
by destroying memory context. However, when I analyzed the usage of 
libpqrcv_processTuples(), I feel it is a memory leak.

A typical call model is like:
```
Caller of walrcv_exec() {
     WalRcvExecResult *res; # define a local variable to store result
     
     res = walrcv_exec(…);  # walrcv_exec will return a result
     
     -> walrcv_exec(…) {
           WalRcvExecResult *walres = palloc0_object(WalRcvExecResult);  # 
allocate memory for result

           walres->status = WALRCV_OK_TUPLES;
           libpqrcv_processTuples(pgres, walres, nRetTypes, retTypes);  # 
libpqrcv_processTuples will fill in result

           -> libpqrcv_processTuples(… walres …) {
                    
                   walres->tuplestore = tuplestore_begin_heap() # allocate 
memory for tuplestore
                   walres->tupledesc = CreateTemplateTupleDesc(nRetTypes); # 
allocate memory for tupledesc
                   
                   attinmeta = TupleDescGetAttInMetadata(walres->tupledesc); # 
allocate memory for attinmeta
           }

           return walres;
     }

    walrcv_clear_result(res); # free res object, nested tuplestore and 
tupledesc are free-ed as well, but attinmeta is leaked
}
```

We can see that, the result object is explicitly free-ed by 
walrcv_clear_result. But the memory pointed by attinmeta is leaked, it will 
only be free-ed when the corresponding memory context is destroyed.

As walrcv_exec() is widely called in a lot of places, it’s hard to tell in 
which memory context libpqrcv_processTuples() runs, so I think attinmeta should 
be free-ed.

But I then noticed that, attinmeta is created by TupleDescGetAttInMetadata() 
that allocates an AttInMetadata object itself as well as several nested 
objects, and there is not a function to deeply free attinmeta, thus a simple 
pfree(attinmeta) won’t resolve the leak problem. Does that mean we 
intentionally to not want to free memory of  AttInMetadata?

So, rather than posting a patch directly, I’d like to confirm with folks who 
are familiar with this area. Is this a real memory leak worthing a fix?

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/






Reply via email to