Skip navigation.
 
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful
FROM : John Engelhart
DATE : Thu Feb 07 02:06:24 2008

On Feb 6, 2008, at 2:12 PM, Alastair Houghton wrote:

> On 6 Feb 2008, at 17:52, Hamish Allan wrote:
>

>> On Feb 6, 2008 2:59 PM, John Engelhart <john.<email_removed>> 
>> wrote:
>>

>>> "I'll take 'Not relevant' for $200 and 'Misunderstands the
>>> fundamentals' for the win, Alex."

>>
>> Speaking of "not relevant" and "misunderstands the fundamentals":
>>
>> 1) UTF8String returns a non-__strong pointer.

>
> __strong isn't a type qualifier, it's an attribute (in the sense of 
> the __attribute__ keyword).  The distinction is perhaps a bit 
> subtle, especially as attributes can be attached to a typedef'd 
> type, but it's the reason that you can put __strong anywhere in a 
> variable declaration and it still has the same effect.  It *isn't* 
> like const or volatile, and the ANSI C rules regarding type 
> qualifiers absolutely *do not* apply.


As I mentioned previously, having no formal grammar of ObjC 2.0 makes 
this point debatable.  Your interpretation that __strong is an 
__attribute__ extension could certainly be true, and is a valid way of 
looking at things.  Without a grammar to guide us, I think both 
interpretations are equally valid.

However, consider for a moment if it was a type attribute, and 
followed type attribute rules, and how this would effect the examples 
cited.  Off the top of my head, I think treating it as a type 
attribute would have prevent every single error I've pointed out. 
Hypothetically, consider if UTF8String propagated the __strong type, 
and the assignment of its pointer to the ivar 'const char *'.

The compiler would fail to compile the code, and generate an error.

Again, I'm pretty sure that every example posted would be caught by if 
__strong was treated as a type attribute.

Since we have two valid ways to interpret the meaning of __strong, I 
believe that the usefulness of catching these errors at compile time 
argues strongly in favor of considering it a type attribute.

>
> Furthermore I *think* (and this is from memory, based on some work I 
> did on GCC several years ago, so I might be wrong) that if you write 
> something like
>
>  void * __strong MyFunction(void);
>
> you'll find that the __strong attribute is attached to the 
> *function* rather than to the type.  In any case it's going to be 
> ignored because __strong only really affects variables, not types or 
> functions.


I hate this part of the language.  Each qualifier has it's quirks, and 
their application is non obvious, including exactly what they apply 
to.  The distinction between

const char * ptr; and
char * const ptr;

isn't terribly clear by just looking at it.  Add to this

const char * const ptr;

Three, totally different things, and using const twice in this way 
just seems like it would be a bug at first glance.
>

>> 2) You fail to copy the data at that pointer.
>> 3) You cry foul when that data disappears.

>
> Well the bug is *either* ignoring the bit in the -UTF8String docs 
> where it says you should copy the string (though that does read like 
> it was only intended to talk about the non-GC case---I just filed <rdar://5727581
> > asking for a clarification), or not using __strong on the variable 
> you're storing the result in.


Actually, I've thought of another example which addresses the use of 
(or lack of) __strong unambiguously and still demonstrates the problem:

#import <Foundation/Foundation.h>

@interface GCTest : NSObject {
  const char *title;
};

- (void)setTitle:(const char *)newTitle;
- (const char *)title;

@end

@implementation GCTest

- (void)setTitle:(const char *)newTitle
{
  printf("Setting title.  Old title: %p, new title %p = '%s'\n", 
title, newTitle, newTitle);
  title = newTitle;
}

- (const char *)title
{
  return title;
}

@end

int main(int argc, char *argv[]) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  GCTest *gcConstTitle = NULL, *gcUTF8Title = NULL;
  void *ptr;

  gcConstTitle = [[GCTest alloc] init];
  gcUTF8Title = [[GCTest alloc] init];

  [gcConstTitle setTitle:"Hello, world!"];
  [gcUTF8Title setTitle:[[NSString stringWithUTF8String:"Hello, world
\xC2\xA1"] UTF8String]];

  NSLog(@"Test: %@", @"hello");
  [[NSGarbageCollector defaultCollector] collectExhaustively];
  NSLog(@"GC test");

  printf("gcConstTitle title: %p = '%s'\n", [gcConstTitle title], 
[gcConstTitle title]);
  printf("gcUTF8Title  title: %p = '%s'\n", [gcUTF8Title title], 
[gcUTF8Title title]);

  [gcConstTitle setTitle:NULL];  // Must clear the pointer before 
popping pool.
  [gcUTF8Title setTitle:NULL];

  [pool release];
  return(0);
}
[<email_removed>] /tmp% gcc -framework Foundation -fobjc-gc-only -o 
gc -g gc.m
[<email_removed>] /tmp% ./gc
Setting title.  Old title: 0x0, new title 0x1ea4 = 'Hello, world!'
Setting title.  Old title: 0x0, new title 0x1011860 = 'Hello, worldĄ'
2008-02-06 18:32:35.712 gc[18108:807] Test: hello
2008-02-06 18:32:35.798 gc[18108:807] GC test
gcConstTitle title: 0x1ea4 = 'Hello, world!'
gcUTF8Title  title: 0x1011860 = 'Hello, world'
Setting title.  Old title: 0x1ea4, new title 0x0 = '(null)'
Setting title.  Old title: 0x1011860, new title 0x0 = '(null)'

Oddly, I had to add a second NSLog() in order to get some kind of 
lossage, but I think it's fair to chalk this up to the semi-random 
nature of allocations.

The above example is now perfectly legal by everyones definition of 
how things were under retain/release, and I correctly clear the 
pointer before it goes out of scope, and demonstrates that the GC 
system can, and does, reclaim live data out from under you.


>

>>> A garbage collection systems sine qua non is to free the programmer
>>> from having to deal with the issues memory allocation.

>>
>> Exactly. So stop getting your knickers in a twist about whether or 
>> not
>> UTF8String actually returns memory from NSAllocateCollectable(), and
>> simply copy the result as required by the documentation for
>> UTF8String.

>
> Indeed, I rather wish I hadn't mentioned NSAllocateCollectable(), 
> since I think it's only muddied the waters further.


I don't.  Again, consider the hypothetical case where __strong is type 
qualifier.  During development of UTF8String, this would cause a 
warning or error (implementation dependent, but I'd argue for error). 
This would highlight the fact that the prototype is discarding a 
critical qualifier.  Assuming that the definition of UTF8String was 
altered to include __strong, my attempt at assigning a __strong 
qualified pointer to a non-strong pointer would instantly be flagged 
and reported by the compiler.

Consider the case of handing a __strong pointer off to a function, 
such as CFStringCreateWithCStringNoCopy().  If the prototype does not 
have __strong for the buffer argument, my example of handing it an 
NSAllocateCollectable pointer would again, instantly trigger a 
compiler warning or error (I vote error considering the consequences).

It's hard to argue that this is not "The Right Thing" to be doing as 
it would have mooted every single point I have raised, and caught all 
of these errors at compile time before they could have become 
problems.  This would have also caught the problem in the example I 
pasted above, at compile time, and alerted me that I just created a 
problem.

Finally, consider the effects of the current behavior of silently 
discarding __strong.  As the example in this message shows, it's 
surprisingly easy to create conditions which violate the conditions 
required for proper GC behavior.

After four months of practical, hands on usage of Leopards GC system, 
my experience is that this is happening far, far more frequently than 
you might think.  I have had to deal with endless problems under GC 
which have all the tell tale signs of race conditions.  Because what 
I'm developing is dual mode, flipping over to retain/release works 
flawlessly, even after intensive multithreaded concurrent extreme 
stress testing.  The retain/release side of thing never crashes, but 
the GC side of things mostly doesn't crash.

I think the evidence I've put forth is pretty strong.  I think the 
example I give in this message addresses everyones concerns regarding 
the use of __strong.  It's pretty clear that I don't need to use 
__strong for the pointer, and that under retain/release methodology, 
it is incapable of freeing the UTF8String buffer while its still in 
use.  It's certainly open to debate how frequently this happens in 
practice.  I have shown that it is possible.  In my opinion, after 
four months of use, this is happening much more frequently than you 
might think at first approximation.  And just like race conditions, it 
gets worse the harder you push, which is to be expected.  It's pretty 
much a ticking time bomb, and everything seems to work fine when 
you're doing development, but then starts failing mysteriously out in 
the field._______________________________________________

Cocoa-dev mailing list (<email_removed>)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/<email_removed>

This email sent to <email_removed>

Related mailsAuthorDate
mlUse of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 4, 02:57
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Quincey Morris Feb 4, 05:09
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful j o a r Feb 4, 08:18
mlre: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Ben Trumbull Feb 4, 10:19
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Alastair Houghton Feb 4, 14:11
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Greg Titus Feb 4, 16:39
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Sean McBride Feb 4, 22:40
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 5, 01:14
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Chris Hanson Feb 5, 02:21
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Jonathon Mah Feb 5, 08:47
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Alastair Houghton Feb 5, 13:40
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 6, 10:39
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Alastair Houghton Feb 6, 12:15
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 6, 15:59
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Michael Tsai Feb 6, 16:12
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful glenn andreas Feb 6, 16:45
mlBug in CF/NSString's no-copy constructors (was Re: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful) Alastair Houghton Feb 6, 16:55
mlRe: Bug in CF/NSString's no-copy constructors (was Re: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful) Michael Tsai Feb 6, 17:46
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Clark Cox Feb 6, 17:47
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Jean-Daniel Dupas Feb 6, 18:05
mlRe: Bug in CF/NSString's no-copy constructors Alastair Houghton Feb 6, 18:46
ml[Moderator] Re: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Scott Anguish Feb 6, 18:46
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Hamish Allan Feb 6, 18:52
mlRe: Bug in CF/NSString's no-copy constructors Michael Tsai Feb 6, 19:29
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Hamish Allan Feb 6, 19:36
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Alastair Houghton Feb 6, 20:12
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful glenn andreas Feb 6, 21:23
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Sean McBride Feb 6, 21:47
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Michael Ash Feb 6, 22:38
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Hamish Allan Feb 6, 23:49
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 7, 02:06
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Hamish Allan Feb 7, 02:40
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Chris Suter Feb 7, 02:48
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 7, 02:48
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Clark Cox Feb 7, 03:52
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful glenn andreas Feb 7, 04:01
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Timothy Reaves Feb 7, 04:08
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Brady Duga Feb 7, 04:22
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 7, 07:14
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 7, 07:14
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Michael Ash Feb 7, 23:58
mlRe: Bug in CF/NSString's no-copy constructors John Engelhart Feb 8, 03:31
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful John Engelhart Feb 8, 05:23
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Greg Parker Feb 8, 05:30
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Michael Tsai Feb 8, 05:56
mlRe: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Hamish Allan Feb 8, 18:35
ml[Moderator] Re: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful Scott Anguish Feb 8, 22:17