• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Accessing buffers in NSData/NSMutableData under garbage collection
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Accessing buffers in NSData/NSMutableData under garbage collection


  • Subject: Re: Accessing buffers in NSData/NSMutableData under garbage collection
  • From: Alastair Houghton <email@hidden>
  • Date: Tue, 19 Feb 2008 11:48:22 +0000

On 19 Feb 2008, at 06:24, Chris Suter wrote:

I don't use garbage collection myself so someone with more experience might know a way of getting interior pointers to work (I believe that's the name for them).

AFAIK the Cocoa GC doesn't support interior pointers; in order for a garbage collector to do so, it has to be able to find the start address of the block to which a given pointer belongs, which has unpleasant performance implications.


You could still be in trouble if you decided to do something like:

float *myArray = NSAllocateCollectable(size * sizeof(float), 0);

// myArray is not referenced after the following line
for (n = 0, myPointer = myArray; n < size; ++n, ++myPointer) {
 // Do something with myPointer
}

In this case, there's nothing stopping the compiler turning it into the same as my first example.

Indeed, the following code is broken, but only when compiled using optimization:


/* ---- tst.m ----------------------------------------------------- */

  #import <Foundation/Foundation.h>

  int
  main (int argc, char **argv)
  {
    float *myArray = NSAllocateCollectable(1000 * sizeof(float), 0);
    unsigned n;
    float *ptr;

    for (n = 0, ptr = myArray; n < 100; ++n, ++ptr) {
      *ptr = 1.0;
    }

    [[NSGarbageCollector defaultCollector] collectExhaustively];

    for (n = 0; n < 100; ++n, --ptr) {
      printf ("%f\n", *ptr);
    }

    return 0;
  }

/* ---------------------------------------------------------------- */

To see it break,

  gcc -O3 -fobjc-gc tst.m -framework Foundation -o tst

then

  MallocScribble=YES ./tst

The fix is, of course, to use "volatile" to prevent the optimization:

float * volatile myArray = NSAllocateCollectable(1000 * sizeof(float), 0);

(Perhaps ironically, __strong is *not* sufficient to prevent this from happening...)

On 19 Feb 2008, at 06:24, Chris Suter wrote:

What is needed, I believe, is a way of getting auto-released memory. This would solve this problem and also things like -[NSString UTF8String] which suffer from the same problem, and are worse because you often want to pass the result of it to library routines (which you have no control over).

Yikes! That's unpleasant. The following, for example, will fail on PowerPC at -O3:


/* ---- tst2.m ---------------------------------------------------- */

  #import <Foundation/Foundation.h>

  extern void foobar (float *ptr);

  int
  main (int argc, char **argv)
  {
    float *myArray = NSAllocateCollectable(1000 * sizeof(float), 0);

    foobar (myArray);

    return 0;
  }

/* ---------------------------------------------------------------- */

/* ---- tst3.m ---------------------------------------------------- */

  #import <Foundation/Foundation.h>

  void
  foobar (float *ptr)
  {
    unsigned n;

    for (n = 0; n < 100; ++n, ++ptr)
      *ptr = 1.0;

    [[NSGarbageCollector defaultCollector] collectExhaustively];

    for (n = 0; n < 100; ++n, --ptr)
      printf ("%f\n", *ptr);
  }

/* ---------------------------------------------------------------- */

Again, to see it break:

gcc -arch ppc -O3 -fobjc-gc tst2.m tst3.m -framework Foundation -o tst2

then

  MallocScribble=YES ./tst2

and again, you need a "volatile" to fix it.

IMHO, as a result, using NSAllocateCollectable() is risky. Worse, however, so is -UTF8String (*):

/* ---- tst4.m ---------------------------------------------------- */

  #import <Foundation/Foundation.h>

  extern void foobar (const char *ptr);

  int
  main (int argc, char **argv)
  {
    NSString *str = [NSString stringWithFormat:@"%d", 1000];

    foobar ([str UTF8String]);

    return 0;
  }

/* ---------------------------------------------------------------- */

/* ---- tst5.m ---------------------------------------------------- */

  #import <Foundation/Foundation.h>

  void
  foobar (const char *ptr)
  {
    unsigned n;

    for (n = 0; n < 3; ++n, ++ptr);

    [[NSGarbageCollector defaultCollector] collectExhaustively];

    for (n = 0; n < 3; ++n, --ptr)
      printf ("x '%c'\n", *ptr, *ptr);
  }

/* ---------------------------------------------------------------- */

which again breaks on PowerPC:

gcc -arch ppc -O3 -fobjc-gc tst4.m tst5.m -framework Foundation -o tst3
MallocScribble=YES ./tst3


and the only way to fix it is to do:

  const char * volatile utf8 = [str UTF8String];

  foobar (utf8);

(or, I suppose, to store it into a __strong global or instance variable first)

:-( :-(

I just filed <rdar://5751702> about this issue. I could cope with having to worry about optimization when calling NSAllocateCollectable(), but surely it's too much to expect us to do so for -UTF8String et al?

I'm not sure what the best fix is for this. Like Chris said, one option would be to allow us to allocate "autoreleased" memory (in which case -UTF8String should probably be doing that too). Or maybe the GC should support interior pointers to memory allocated with NSAllocateCollectable()?

Kind regards,

Alastair.

(*) And before John Engelhart jumps on this statement and claims he was "right all along", he was talking about an entirely separate problem. This is specifically a problem caused by the lack of interior pointer support, and it *only happens* if the library routine being called modifies (the only copy of) the pointer it's passed without storing it anywhere first. I doubt that's very common in practice, but it is a risk as the (admittedly contrived) examples above demonstrate.

--
http://alastairs-place.net


_______________________________________________

Cocoa-dev mailing list (email@hidden)

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:
This email sent to email@hidden


  • Follow-Ups:
    • Re: Accessing buffers in NSData/NSMutableData under garbage collection
      • From: Chris Suter <email@hidden>
    • Re: Accessing buffers in NSData/NSMutableData under garbage collection
      • From: Quincey Morris <email@hidden>
References: 
 >Accessing buffers in NSData/NSMutableData under garbage collection (From: Rick Hoge <email@hidden>)
 >Re: Accessing buffers in NSData/NSMutableData under garbage collection (From: Adam P Jenkins <email@hidden>)
 >Re: Accessing buffers in NSData/NSMutableData under garbage collection (From: mmalc crawford <email@hidden>)
 >Re: Accessing buffers in NSData/NSMutableData under garbage collection (From: Adam P Jenkins <email@hidden>)
 >Re: Accessing buffers in NSData/NSMutableData under garbage collection (From: Adam P Jenkins <email@hidden>)
 >Re: Accessing buffers in NSData/NSMutableData under garbage collection (From: Chris Suter <email@hidden>)

  • Prev by Date: Re: How to detect focus on an NSTextField
  • Next by Date: Re: NSTask output only after termination of NSTask
  • Previous by thread: Re: Accessing buffers in NSData/NSMutableData under garbage collection
  • Next by thread: Re: Accessing buffers in NSData/NSMutableData under garbage collection
  • Index(es):
    • Date
    • Thread