1.3.22: memory leaks

Message ID d25t55$dgq$1@video.local.muempf.de
State New
Headers

Commit Message

Stefan Huelswitt March 27, 2005, 9:07 a.m. UTC
  Hi,
while investigating VDR with valgrind and other memory tracing
tools, I found two places where memory leaks.

First is in dvbplayer.c, where the Action() code builds a frame
from the replayed file (readFrame). If the ringbuffer is already
full, this frame cannot be put immediately. If Empty() is called
in such a situation, the premade frame is lost.
Solution:


Regards.
  

Comments

Clemens Kirchgatterer March 27, 2005, 9:39 a.m. UTC | #1
s.huelswitt@gmx.de (Stefan Huelswitt) wrote:

> Second is in epg.c tComponent::FromString(). I cannot find
> anything bad with the code there, but valgrind reports a lot of
> memory leaks with the sscanf() call. So I guessed that sscanf() is
> leaking internaly when used with "%a[\n]" (at least with my glibc
> version 2.2.5). After changing to code to the suggestion below,
> the leaks disappeared:

from man sscanf:

a	Indicates  that  the  conversion  will be s, the needed
	memory space for the string will be malloc'ed  and the
	pointer to  it will  be assigned to the char pointer
	variable, which does not have to be initialized before. 

so, yes, the user is responsible for freeing memory allocated by sscanf.

clemens
  
Stefan Huelswitt March 27, 2005, 11:51 a.m. UTC | #2
On 27 Mar 2005 Clemens Kirchgatterer <clemens@1541.org> wrote:
> s.huelswitt@gmx.de (Stefan Huelswitt) wrote:
> 
>> Second is in epg.c tComponent::FromString(). I cannot find
>> anything bad with the code there, but valgrind reports a lot of
>> memory leaks with the sscanf() call. So I guessed that sscanf() is
>> leaking internaly when used with "%a[\n]" (at least with my glibc
>> version 2.2.5). After changing to code to the suggestion below,
>> the leaks disappeared:
> 
> from man sscanf:
> 
> a	Indicates  that  the  conversion  will be s, the needed
> 	memory space for the string will be malloc'ed  and the
> 	pointer to  it will  be assigned to the char pointer
> 	variable, which does not have to be initialized before. 
> 
> so, yes, the user is responsible for freeing memory allocated by sscanf.

Yes, of course. I can read man pages ;)

This is not what I'm talking about. The malloc memory is free'd
by VDR, but there is still some memory leaked. I think it's
internaly lost.
This can be proven with my patch. If the %a[ is obmitted, there
is no leak.

Regards.
  
Darren Salt March 27, 2005, 4:44 p.m. UTC | #3
I demand that Stefan Huelswitt may or may not have written...

[snip]
> The malloc memory is free'd by VDR, but there is still some memory leaked.
> I think it's internally lost. This can be proven with my patch. If the %a[
> is omitted, there is no leak.

And if you free(description) before the sscanf()?
  
Stefan Huelswitt March 27, 2005, 6:15 p.m. UTC | #4
On 27 Mar 2005 Darren Salt <linux@youmustbejoking.demon.co.uk> wrote:

> I demand that Stefan Huelswitt may or may not have written...
> 
> [snip]
>> The malloc memory is free'd by VDR, but there is still some memory leaked.
>> I think it's internally lost. This can be proven with my patch. If the %a[
>> is omitted, there is no leak.
> 
> And if you free(description) before the sscanf()?

I did that. description is never != NULL when the code is called.

Regards.
  
Klaus Schmidinger May 5, 2005, 12:52 p.m. UTC | #5
Stefan Huelswitt wrote:
> Hi,
> while investigating VDR with valgrind and other memory tracing
> tools, I found two places where memory leaks.
> 
> First is in dvbplayer.c, where the Action() code builds a frame
> from the replayed file (readFrame). If the ringbuffer is already
> full, this frame cannot be put immediately. If Empty() is called
> in such a situation, the premade frame is lost.
> Solution:
> 
> --- dvbplayer.c	2005-01-14 15:00:56.000000000 +0100
> +++ dvbplayer.c	2005-03-26 21:41:23.000000000 +0100
> @@ -296,6 +296,7 @@
>       nonBlockingFileReader->Clear();
>    if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
>       readIndex = writeIndex;
> +  delete readFrame;
>    readFrame = NULL;
>    playFrame = NULL;
>    ringBuffer->Clear();

Very well spotted!

I believe the same should be done in cDvbPlayer::~cDvbPlayer()
(just tested it, it also happens there).

Klaus
  
Stefan Huelswitt May 5, 2005, 1:07 p.m. UTC | #6
On 05 May 2005 Klaus Schmidinger <Klaus.Schmidinger@cadsoft.de> wrote:
> Stefan Huelswitt wrote:
>> Hi,
>> while investigating VDR with valgrind and other memory tracing
>> tools, I found two places where memory leaks.
>> 
>> First is in dvbplayer.c, where the Action() code builds a frame
>> from the replayed file (readFrame). If the ringbuffer is already
>> full, this frame cannot be put immediately. If Empty() is called
>> in such a situation, the premade frame is lost.
>> Solution:
>> 
>> --- dvbplayer.c	2005-01-14 15:00:56.000000000 +0100
>> +++ dvbplayer.c	2005-03-26 21:41:23.000000000 +0100
>> @@ -296,6 +296,7 @@
>>       nonBlockingFileReader->Clear();
>>    if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
>>       readIndex = writeIndex;
>> +  delete readFrame;
>>    readFrame = NULL;
>>    playFrame = NULL;
>>    ringBuffer->Clear();
> 
> Very well spotted!
> 
> I believe the same should be done in cDvbPlayer::~cDvbPlayer()
> (just tested it, it also happens there).

True, but not as common as the other place.

What do you think about Daniels fix to the asprintf() problem?

Regards.
  
C.Y.M May 5, 2005, 1:14 p.m. UTC | #7
Klaus Schmidinger wrote:
> Stefan Huelswitt wrote:
> 
>> Hi,
>> while investigating VDR with valgrind and other memory tracing
>> tools, I found two places where memory leaks.
>>
>> First is in dvbplayer.c, where the Action() code builds a frame
>> from the replayed file (readFrame). If the ringbuffer is already
>> full, this frame cannot be put immediately. If Empty() is called
>> in such a situation, the premade frame is lost.
>> Solution:
>>
>> --- dvbplayer.c    2005-01-14 15:00:56.000000000 +0100
>> +++ dvbplayer.c    2005-03-26 21:41:23.000000000 +0100
>> @@ -296,6 +296,7 @@
>>       nonBlockingFileReader->Clear();
>>    if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
>>       readIndex = writeIndex;
>> +  delete readFrame;
>>    readFrame = NULL;
>>    playFrame = NULL;
>>    ringBuffer->Clear();
> 
> 
> Very well spotted!
> 
> I believe the same should be done in cDvbPlayer::~cDvbPlayer()
> (just tested it, it also happens there).
> 

Like this?

cDvbPlayer::~cDvbPlayer()
{
  Detach();
  Save();
  delete index;
  delete fileName;
  delete backTrace;
  delete readFrame;
  delete ringBuffer;
}

Best Regards,
  
Klaus Schmidinger May 5, 2005, 1:23 p.m. UTC | #8
Stefan Huelswitt wrote:
> ...
> What do you think about Daniels fix to the asprintf() problem?

I've adopted that one, too.

Klaus
  
Klaus Schmidinger May 5, 2005, 1:24 p.m. UTC | #9
C.Y.M wrote:
> Klaus Schmidinger wrote:
> ...
>>I believe the same should be done in cDvbPlayer::~cDvbPlayer()
>>(just tested it, it also happens there).
>>
> 
> 
> Like this?
> 
> cDvbPlayer::~cDvbPlayer()
> {
>   Detach();
>   Save();
>   delete index;
>   delete fileName;
>   delete backTrace;
>   delete readFrame;
>   delete ringBuffer;
> }

Yes.

Klaus
  

Patch

--- dvbplayer.c	2005-01-14 15:00:56.000000000 +0100
+++ dvbplayer.c	2005-03-26 21:41:23.000000000 +0100
@@ -296,6 +296,7 @@ 
      nonBlockingFileReader->Clear();
   if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
      readIndex = writeIndex;
+  delete readFrame;
   readFrame = NULL;
   playFrame = NULL;
   ringBuffer->Clear();

Second is in epg.c tComponent::FromString(). I cannot find
anything bad with the code there, but valgrind reports a lot of
memory leaks with the sscanf() call. So I guessed that sscanf() is
leaking internaly when used with "%a[\n]" (at least with my glibc
version 2.2.5). After changing to code to the suggestion below,
the leaks disappeared:

--- epg.c	2005-02-19 12:35:00.000000000 +0100
+++ epg.c	2005-03-27 10:53:06.000000000 +0200
@@ -28,13 +28,12 @@ 
 bool tComponent::FromString(const char *s)
 {
   unsigned int Stream, Type;
-  int n = sscanf(s, "%X %02X %3c %a[^\n]", &Stream, &Type, language, &description);
-  if (n != 4)
+  char buf[512];
+  int n = sscanf(s, "%X %02X %3c %511[^\n]", &Stream, &Type, language, buf);
+  if (n==4 && !isempty(buf))
+     description = strdup(buf);
+  else
      description = NULL;
-  else if (isempty(description)) {
-     free(description);
-     description = NULL;
-     }
   stream = Stream;
   type = Type;
   return n >= 3;