I have to slightly disagree with the analysis that Richard did provide. For me 
it seems like the autorelease pool is not directly released or cleared in the 
code. It might get automatically cleared, as Richard wrote, when the main 
thread exits. But I am not that sure about this, especially as we are talking 
about the situation for the memory checker and anyway it is good practice to 
release an autorelease pool, when it is no longer needed.

Overall I am also not that convinced we are gaining anything from this specific 
approach to use valgrind. Normally a library like GNUstep would provide a list 
of ignores for valgrind. Otherwise you will get way too many false positives. 
When I was using valgrind to detect memory leaks about ten years ago, I tried 
to ignore the initially allocated data and only looked at things that are used 
in the actual running of the code. Best in a loop, so that they show up 
multiple times.

Hope this helps,
Fred


> Am 18.01.2025 um 16:28 schrieb R Frith-Macdonald 
> <[email protected]>:
> 
> 
> On 18/01/2025 08:57, Daniel Santos wrote:
>> Hi,
>> 
>> I am attaching a tgz with a small example project. It has a Makefile (the 
>> Makefile is called Makefile.gnustep and there should be a symlink to it)
>> the executable is written into a bin subdirectory. The code is just a class 
>> that creates a string and exits.
>> 
>> I ran it with valgrind —leak-check=yes and am attaching the output from that.
>> From what I see in the output, the only case that resembles what I saw when 
>> I ran valgrind on my library is a leak in a [NSString initWithFormat] call 
>> (Client.m:15) )which is the one that calls malloc in gnustep library.
>> 
>> There is a lot of other output that I don’t know if they are real leaks or 
>> not, maybe someone can shed some light on it as I don’t understand them.
>> 
>> Thanks
> 
> Please excuse stuff you already know ... I decided to take this as an
> opportunity to add an example to the GNUstep-base programming manual, so
> I aimed it at a beginner. I hope it helps though.
> 
> Looking at the code:
> 
> #import "Client.h" @implementation Client - (void) executeCallSequence
> 
> { NSString *str = [NSString stringWithFormat: @"one little string :
> %d\n", 100]; const char *strCharPtr = [str cString]; } @end int main(int
> argv, char** argc)
> 
> { Client *client = [[Client alloc] init];
> 
> [[NSAutoreleasePool alloc] init]; [client executeCallSequence];
> 
> return 0;
> 
> } So, what do we expect this to do?
> 
> Firstly this creates a Client instance, owned by the main function. This
> is because +alloc returns an instance owned by the caller, and -init
> consumes its receiver and returns an instance owned by the caller, so
> the alloc/init sequence produces an instance owned by the main function.
> 
> Next, creates/enters an autorelease pool, owned by the main function.
> 
> Next, executes the method:
> 
> Creates an NSString which is NOT owned by the method.
> 
> The +stringWithFormat: method creates a new inmstance and adds it to the
> current autorelease pool before returning it.
> 
> Creates a C string, which is NOT owned by the method.
> 
> A non-object return value can't be retained or released, but it conforms
> to the convention that the memory is not owned by the caller, so the
> caller need not free it. The -cString method is free to manage that
> however it likes (for instance it might return a pointer to some
> internal memory which exists until the NSString object is deallocated),
> but typically what's returned is a pointer to memory inside some other
> object which has been autoreleased.
> 
> A simple look at the basic retain count and autorelease rules would say
> that all the memory is leaked (because the program contains no call to
> release anything), but there's a bit of behind the scenes magic: when a
> thread exits it releases all the autorelease pools created in it which
> were not already released.
> 
> So when you consider that, you can see that the autorelease pool is
> deallocated so the memory of the pool is actually freed, and the memory
> of the NSString and C-String inside it are therefore also freed.
> 
> This leaves us with the memory of the Client object being leaked.
> However, the idea that any unfreed memory is a leak is too simplistic
> (leak checkers would be useless if they reported so much) so the leak
> checker only reports some unfreed memory ... stuff that can't be reached
> from various standard routes. The main case is that anything pointed to
> by global or static variables is not considered leaked, but also
> anything pointed to by a variable in the main() function is not
> considered leaked. This is why the Client instance is not reported.
> 
> So, if automated cleanup at exit covers the strings and the Client
> instance is not counted as a leak, what does get logged?
> 
> In your logs I see leaks reported for the runtime functions
> class_addMethod and__objc_exec_class. These are old and minor runtime
> library bugs. If you update to using the latest runtime library from the
> git repository, these leak reports should go away.
> 
> The other logs look like leftovers from setting up the main thread;
> something normally counted as still reachable (and therefore not
> reported as leaks) on program exit. They don't show up in LeakSanitizer,
> but I guess valgrind has different rules about what it counts as leaks.



Reply via email to