Saturday, August 18, 2012

Debugging with ARC and Zombies enabled

If you tried to debug your app with zombies enabled under ARC, you may have noticed that you don’t get zombies anymore. That’s most probably because of a bug in the Foundation framework that affects iOS 5 and OS X 10.7. This bug prevents ARC from "cleaning up" instance variables at deallocation-time according to Apple Technical Q&A QA1758. Apple strongly encourages you to run your app on an iOS 6+, or OS X 10.8+ system when debugging with Zombies.
In the meantime, you can workaround this bug if you are using ARC and trying to debug zombies on older systems. Just compile this NSObject+ARCZombie.m file in your project and ivars will be automatically deallocated under ARC when zombies are enabled, as it should be.
Now you might think Hey, you are swizzling dealloc, isn't that dangerous? Well, yes it is, but note that the dealloc method is only swizzled when the NSZombieEnabled environment variable is enabled, so even if this code slips in your release build, il will cause no harm at all.

UPDATE: After I posted this, Greg Parker warned me on twitter:

@0xced That'll cause over-release of associated objects on some systems.

So use this workaround with care and remember that the best solution is what Apple recommends: run your app on an iOS 6+ or OS X 10.8+ system when debugging with Zombies.

Wednesday, August 08, 2012

Prepare your apps for the iPhone 5

Earlier today, my friend Peter Steinberger asked:

Does anyone know what does “special iPhone Simulator tweaks” are? I’d love to test my stuff with different resolutions. http://9to5mac.com/2012/08/07/upcoming-ios-6-is-scalable-to-taller-640-x-1136-iphone-display-shows-possible-next-generation-device-user-interface/

So I investigated, and found a pretty elegant solution. Without further ado, here is how to change the size of the iOS simulator in order to test your apps in resolutions never seen before.

  1. Download File.txt into ~/Library/Application Support/iPhone Simulator (don't change the name of File.txt)
  2. Edit /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone Simulator.app/Contents/Resources/Devices/iPhone (Retina).deviceinfo/Info.plist and add the following keys:
    <key>eagle</key>
    <string>640</string>
    <key>giraffe</key>
    <string>1136</string>
  3. Add setenv("CLASSIC", "0", 1); just before UIApplicationMain in your main.m file in order to support any simulator version.
  4. Quit the iOS Simulator app

You are now ready to test your apps on the rumored 640×1136 new iPhone.

This hack works on Xcode 4.4.1+ and the iPhone 5.1+ Simulator with the iPhone (Retina) device.

Thursday, May 26, 2011

How to restore Apple Front Row Trailers

English version below

Comme vous avez pu le constater, Front Row Trailers ne fonctionne plus. Étant donné que Front Row est absent de Lion, je ne mettrai plus à jour Front Row Trailers.

Voici donc la méthode pour remettre les bandes-annonces originales d'Apple:

  1. Téléchargez et décompressez Restore Apple Trailers
  2. Double-cliquez sur le fichier Restore Apple Trailers.command
  3. Entrez votre mot de passe


As you probably have noticed, Front Row Trailers is not working anymore. Since Front Row is missing in Lion, I have no plan to update Front Row Trailers.

So here is how to restore factory Apple trailers:

  1. Download and decompress Restore Apple Trailers
  2. Double-click on Restore Apple Trailers.command
  3. Enter your password

Monday, February 14, 2011

Using Ingredients as Xcode documentation browser

Xcode 3.2.3 documentation browser was quite broken: ⌘ + ⌥ + double click on a method or function would open the documentation browser but would not scroll to the method you just asked documentation for. So I started to write an Xcode plugin to open Ingredients instead. Then Xcode 3.2.5 was released (I skipped version 3.2.4) and this annoying bug was fixed, so I did not bother to publish my plugin. But recently, I read on twitter that [RED4CTED] documentation browser was even more broken, so I decided it was time to release my Xcode-Ingredients plugin.

Note that the plugin is written for Xcode 3, so things have probably changed in [RED4CTED] (which I have not yet tried). If you are brave enough to use [RED4CTED], that you know a bit about Xcode plugins (@kodz, @rentzsch, @tjw?) and that you would like to use Ingredients for reading the documentation, please have a look and adapt the plugin for [RED4CTED]. In order to discover the searchForAPIString: method, I just set a breakpoint on makeKeyAndOrderFront: and looked at the backtrace, but I'm not sure if this technique is still applicable.

I will update this blog post as soon as someone can get the plugin to work with [RED4CTED].

Saturday, September 11, 2010

CLLocation getDistanceFrom: vs distanceFromLocation:

In Backwards Compatibility if Apple Starts Polishing, Oliver Drobnik explains how he solved the getDistanceFrom: vs distanceFromLocation: problem. His solution involves a new method (distanceBetweenLocation:andLocation:) and eight lines of code for calling getDistanceFrom: through a NSInvocation.

Wouldn't it be nice if instead you could use [aLocation distanceFromLocation:anotherLocation] everywhere in your code, while still retaining backward compatibility? Enter the Objective-C runtime! In your main.m file, first #import <objc/runtime.h> and at the very beginning of your main function, add this:


Method getDistanceFrom = class_getInstanceMethod([CLLocation class], @selector(getDistanceFrom:));
class_addMethod([CLLocation class], @selector(distanceFromLocation:), method_getImplementation(getDistanceFrom), method_getTypeEncoding(getDistanceFrom));


Here you go, -[CLLocation distanceFromLocation:] available at runtime in any iOS version with only two lines of code. Note that on iOS 3, class_addMethod will add the distanceFromLocation: method to the CLLocation class using getDistanceFrom: implementation. On iOS 4, class_addMethod will do nothing as the method already exists.

Friday, July 02, 2010

Using SDK 3.1.3 with iPhone SDK 4

In iPhone SDK 4 Apple has removed all 3.x SDKs. I think that was not a very good idea to say the least. I can understand Apple wants developers to adopt the new features of iOS 4, but breaking zillions of Xcode projects is probably not a good way to win the hearts of those developers. Well, this is probably not Apple's goal anyway.

Sure there is a way to get your projects working again with the iPhone SDK 4, just set the Base SDK of your project to iOS 4:

Base SDK 4

and set the Deployment Target to iOS 3:

Deployment Target 3

This will get your projects compile and run again on both iOS 3 and 4. That's fine. Well, except when you want to make sure your project do not use any new iOS 4 only API.

The problem is, code like this will now compile without any warning or error:

[[NSUserDefaults standardUserDefaults] setURL:defaultURL forKey:@"DefaultURL"];

It's easier than you think to use a shiny new API without even noticing you are using something not available on iOS 3. This setURL:forKey: method is new in iOS 4 so this code will fail with an unrecognized selector exception when run on iOS 3. Unfortunately, the only way to catch this kind of oversight is to run it on an iOS 3 device. Or you can read the documentation of every single method and function you are calling to make sure it was not introduced in iOS 4. But this does not seem very reasonable, does it? The tools should help us detecting these problems at compile time, not runtime!

Here is how to get Xcode 3.2.3 and iPhone SDK 4 working with SDK 3.1.3.

  1. Log in to the iOS Dev Center
  2. Download the iPhone SDK 3.1.3 into ~/Downloads
  3. Run the install-iphone-sdk-3.1.3.sh script
  4. Quit and relaunch Xcode
  5. Duplicate your Debug configuration and rename it to SDK 3.1.3 Check
  6. Set the Base SDK of this new configuration to iPhone Simulator 3.1.3
  7. Add a User-Defined Setting GCC_OBJC_ABI_VERSION and set its value to 1 (one)
  8. Select GCC_OBJC_ABI_VERSION and choose Add Build Setting Condition from the gear pop-up button at the lower left of the window.
  9. Select Any iPhone Simulator and Any Architecture

There you go! By selecting the SDK 3.1.3 Check configuration, you get compile time check for misusing iOS 4 only APIs when targeting iOS 3.

Note that compiling with the iPhone Simulator 3.1.3 SDK and running in Xcode 3.2.3 simulator is not supported. What you get with this hack is just a compile time check of the APIs you are using. So do not expect to run your app on a 3.1.3 simulator.

Wednesday, June 02, 2010

Fixing -[NSMutableURLRequest setValue:forHTTPHeaderField:]

UPDATE

This problem is fixed as of Mac OS X 10.8.3+ and iOS 5.1+. I have no idea when it was actually fixed since radar sucks so much.

The problem

From NSMutableURLRequest setValue:forHTTPHeaderField: documentation:
In keeping with the HTTP RFC, HTTP header field names are case-insensitive.

I see three problems with this.
  1. Assuming all HTTP implementations are RFC compliant is foolish to say the least.
  2. Enforcing case-insensitivity is nonsense.
  3. This bit of documentation is accurate, the case of header fields is actually changed.
Trying this
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.example.com"]];
[request setValue:@"MyValue" forHTTPHeaderField:@"MyField"];
NSLog(@"result: %@", [request allHTTPHeaderFields]);
outputs
    result: {
Myfield = MyValue;
}
Notice how the 'F' of MyField was lowercased, that sucks! If the HTTP server you are trying to communicate with is case-sensitive, you are screwed. I filed radar #8029516, which is a duplicate of radar #3131623, which means there is almost no chance to have this fixed anytime soon.

When this happens, you should contact the server administrator asking for a case-insensitive implementation. But in the meantime, if you badly need to preserve the case of your headers, read on.

The investigation

First, let's fire otx to disassemble the Foundation framework in order to have a look at setValue:forHTTPHeaderField: implementation. I strongly suggest you to use otx version from subversion trunk, as it is better at resolving symbols in tail call optimizations (fixed in r553).

Excerpt from otx 0.16b:
   +18  [...]  movl     %eax,0x08(%ebp)
+21 [...] leave
+22 [...] jmpl 0x002c52bb

Excerpt from otx trunk:
   +18  [...]  movl     %eax,0x08(%ebp)
+21 [...] leave
+22 [...] jmpl 0x002c52bb _CFURLRequestSetHTTPHeaderFieldValue

Much better, isn't it?

So let's go through the function calls of setValue:forHTTPHeaderField:. With a basic static analysis of the Foundation and CFNetwork disassemblies, we can draw the following call path:
-[NSMutableURLRequest(NSMutableHTTPURLRequest) setValue:forHTTPHeaderField:]
CFURLRequestSetHTTPHeaderFieldValue()
URLRequest::setHTTPHeaderFieldValue()
HTTPRequest::setHeaderFieldValue()
CFHTTPMessageSetHeaderFieldValue()
HTTPMessage::setHeaderFieldValue()
_CFCapitalizeHeader()

_CFCapitalizeHeader looks like a very good candidate for being the bastard changing the case of our headers. A quick search reveals the source code of CFNetwork that was open source long time ago. Although the open source implementation does not exactly match what we see in the disassembly (it is now using toupper instead of ch + 'A' - 'a' for example), we are now absolutely sure that _CFCapitalizeHeader is the function responsible for messing with our headers.

Now, let's check is if there is a path that will not call _CFCapitalizeHeader and if we can somehow influence the condition that would avoid the call to _CFCapitalizeHeader. This is quickly checked, especially if you enabled the Separate logical blocks option of otx (-b option for cli).
HTTPMessage::setHeaderFieldValue(__CFString const*, __CFString const*)
+0 000515a4 55 pushl %ebp
+1 000515a5 89e5 movl %esp,%ebp
+3 000515a7 83ec28 subl $0x28,%esp
+6 000515aa 8b4508 movl 0x08(%ebp),%eax
+9 000515ad 8975f8 movl %esi,0xf8(%ebp)
+12 000515b0 8b7510 movl 0x10(%ebp),%esi
+15 000515b3 897dfc movl %edi,0xfc(%ebp)
+18 000515b6 8945f4 movl %eax,0xf4(%ebp)
+21 000515b9 8b450c movl 0x0c(%ebp),%eax
+24 000515bc 890424 movl %eax,(%esp)
+27 000515bf e88a26fbff calll __CFCapitalizeHeader
+32 000515c4 c744240cffffffff movl $0xffffffff,0x0c(%esp)
+40 000515cc 89742408 movl %esi,0x08(%esp)
+44 000515d0 89c7 movl %eax,%edi

We see that there is no path that avoid the call to _CFCapitalizeHeader. So we are left with the last resort solution: patching _CFCapitalizeHeader. With APE Lite, function patching is very easy. You first use APEFindSymbol() to find the address of a non-exported symbol (i.e. __CFCapitalizeHeader), then APEPatchCreate() to replace a function implementation with your own, while still keeping a reference to the original implementation. On iPhone OS, you can use APE Lite+arm (my implementation of the APE Lite API using MobileSubstrate).

The solution

NSMutableURLRequest+CaseSensitive is a category on NSMutableURLRequest that adds these three methods:
   - (void) setAllHTTPHeaderFields:(NSDictionary *)headerFields caseSensitive:(BOOL)caseSensitive;
- (void) setValue:(NSString *)value forHTTPHeaderField:(NSString *)field caseSensitive:(BOOL)caseSensitive;
- (void) addValue:(NSString *)value forHTTPHeaderField:(NSString *)field caseSensitive:(BOOL)caseSensitive;

Just pass caseSensitive:YES for preserving the case of your header fields.

Warning: you SHOULD NOT use this in production code. But hey, HTTP implementations SHOULD be case-insensitive ;-)

Thursday, April 08, 2010

ABGetMe with the iPhone SDK

Unlike the Mac Address Book API, the iPhone Address Book API does not come with the ABGetMe function. That's a pity, but we can do something about it.

Recently, I used MFMailComposeViewController for the first time and I realized that it was displaying my e-mail address. Nicolas Seriot already demonstrated how to retrieve all your e-mail account information in SpyPhone, but I felt there was a more lightweight method for retrieving the e-mail addresses by taking advantage of the MessageUI framework. A class-dump and five minutes later, here is my solution:

Sunday, January 03, 2010

Jasscore pour iPhone

Ma première application iPhone, Jasscore (lien iTunes) est enfin disponible sur l'AppStore au prix de 1.10 CHF. C'est une ardoise virtuelle qui vous permet de compter vos points et ceux de votre adversaire au jass (chibre, mise, etc.)

Les features

  • En français et en allemand
  • Editez le nom des équipes et les scores à atteindre
  • Notez les scores et les annonces
  • Multiplication des scores de 1x à 7x
  • Grand affichage afin que tous les joueurs puissent suivre les scores

Les captures d'écran


Score
Réglage
Grand Affichage

Je suis ouvert à vos suggestions, alors n'hésitez pas à laisser un commentaire ou à m'envoyer un e-mail.

Saturday, November 07, 2009

CLAlert: NSAlert done right

From NSAlert documentation:

Currently, there is no visual difference between informational and warning alerts.

This was written at the time of Panther and this is still true in Snow Leopard. So why the hell is the setAlertStyle: method provided?

NSCriticalAlertStyle
This style causes the icon to be badged with a caution icon.

A caution icon, for a critical alert? That does not make sense!

Here are screenshots of the default behaviours with the three different alert styles:







The documentation is unfortunately right: there is no difference between the informational and the warning style. The critical style is indeed badged with a caution icon.

As you probably have guessed from the title of this post, I am not happy with this behavior, so I have written a class, CLAlert (MIT License) that displays alerts the way I think it should be done. I.e. a note icon for an informational alert, a caution icon for a warning alert and a stop icon for a critical alert as you can see on these screenshots.







CLAlert is a drop-in replacement for NSAlert. It requires at lest Mac OS X 10.5.

Thursday, November 05, 2009

Watch a large number of icons with Preview.app

Browsing .icns files in Preview.app can be painful. If you try to open all the icons of the CoreTypes bundle for example with the following command

open /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/*icns

you will get this view:


All the different sizes of the .icns are displayed, which makes it quite unpleasant to browse.

F-Script Anywhere to the rescue!

Install F-Script Anywhere into Preview, then do

  1. FSA → New F-Script Workspace

  2. Click the Browser For Target… button

  3. Click on one of the icons

  4. Choose the PVIKImageBrowserView object

  5. In the F-Script Object Browser, name the PVIKImageBrowserView browserView


Finally, in the F-Script interpreter, paste the following code:
groups := browserView layoutManager groups.
count := groups count.
0 to:count-1 do: [:i | browserView collapseGroup:(groups objectAtIndex:i)]


Tada, a nice browsable view of your icons!

Wednesday, August 19, 2009

Booting from a dmg

I was pointed by Jean-Francois Roy that it is possible to boot off a dmg.

It's a simple two steps process using bootfolder:

./makebootfolder /Path/to/OperatingSystem.dmg
sudo ./blessbootfolder /Path/to/OperatingSystem.bootfolder

But beware: you better not have a space in the path to the dmg or in the dmg itself. If you happen to try this trick with a space in the path to the boot folder, then your Mac will brick. In verbose startup, you will get

Error loading kernel 'mach_kernel' (0x9)

If you can't boot anymore, download rEFIt and burn it onto a CD. Then boot on the CD by pressing the C key. You should see something looking like this (maybe without the linux and windows partitions):



Just press enter and you should be able to boot your Mac.

Wednesday, April 08, 2009

Extract UIKit artwork

While writing an iPhone application (more about it on this blog soon), I wanted to tint my UIAlertView with the same color I tinted my other controls. Maybe this is not a good idea, but I wanted to try anyway. Unfortunately, only UISearchBar, UISegmentedControl, UINavigationBar and UIToolbar have the tintColor property. So I started digging into UIKit. The first place to look was obviously the -(void)[UIAlertView(Private) drawRect:] method. To draw its background, a UIAlertView calls _popupAlertBackground which in turn call _UIImageWithName(@"UIPopupAlertSheetBackground.png"). This file probably lies inside the UIKit.framework would think a Mac developer. In fact it is not there. Only two pngs are there: DefaultWallpaper-iPhone.png and DefaultWallpaper-iPod.png. So, where is it?

It is in fact somehow embedded in the Other.artwork file which contains UIKit artwork. This file is memory mapped at application startup, probably for performance reasons and the content is easily accessed with the private _UIImageWithName() function. _UIImageWithName looks up in a dictionary that associates a file name to some memory location that contains the actual image data.

Now, it would be cool to extract all this content to see what artwork UIKit contains. It turns out to be quite easy. The only trick is to find a reference to the dictionary containing all the file names. Check my UIKit Artwork Extractor project on github to see how it works.

In an attempt to encourage comments, I'm offering a beer at NSConference to the first person who will clearly explain how to find the magic address of the images dictionary (except for Nicolas who knows the answer already) and I'm offering two beers to the one who provides a cleaner way to obtain a reference to the dictionary that is not UIKit version specific ;-)

Edit: I have updated the code so that it is not UIKit version specific, so I won the beers myself that I'm going to drink right away.

Monday, March 23, 2009

chmod, ACL and symbolic links

Let's say you want to set an ACL on a symbolic link. So you try the -h option of chmod that is documented to change the mode of the link itself rather than the file that the link points to.

  $ ln -s aFileThatDoesNotExist myLink
$ /bin/chmod -h +a "everyone allow delete" myLink
chmod: Failed to set ACL on file 'myLink': No such file or directory

So, it seems myLink was followed even though we passed the -h option. Let's try with a link that points to an existing file:

  $ touch aFileThatExist
$ ln -fs aFileThatExist myLink
$ /bin/chmod -h +a "everyone allow delete" myLink
$ ls -le myLink aFileThatExist
-rw-r--r--+ 1 cluthi staff 0 5 mar 18:11 aFileThatExist
0: group:everyone allow delete
lrwxr-xr-x 1 cluthi staff 14 5 mar 18:12 myLink -> aFileThatExist

Our hypothesis is confirmed, the link was followed. Let's investigate and have a look at chmod source code (file_cmds-188 on darwinsource).

chmod.c:125 variable hflag is set to true if the -h argument is passed
chmod.c:388 function modify_file_acl() is called, the hflag is not passed to this function

Doh, lazy boys! Let's patch it and add a follow argument to the modify_file_acl() function:
int modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow);
and call it with modify_file_acl(..., !hflag)

From acl_set(3) man: The acl_set_link_np() function acts on a symlink rather than its target, if the target of the path is a symlink. Perfect, that's what we need: we must call acl_set_link_np instead of acl_set_file in order not to follow the link.

chmod_acl.c:807 acl_set_file is called: (0 != acl_set_file(path, ACL_TYPE_EXTENDED, oacl))
Replace with (0 != (follow ? acl_set_file(path, ACL_TYPE_EXTENDED, oacl) : acl_set_link_np(path, ACL_TYPE_EXTENDED, oacl)))

With this small modifications, the -h option should be respected. Rebuild chmod and try again:

  $ ./chmod -h +a "everyone allow delete" myLink
chmod: Failed to set ACL on file 'myLink': Operation not supported
$ ln -fs aFileThatDoesNotExist myLink
$ ./chmod -h +a "everyone allow delete" myLink
chmod: Failed to set ACL on file 'myLink': Operation not supported

Now, whether the link points to an existing file or not, we get the Operation not supported error. That's better diagnostic, but not exactly what we expected :-( So, why is it not supported? Let's dig a bit more. acl_set_link_np implementation is found at Libc-498.1.5/posix1e/acl_file.c:175 and is:

  return(acl_set_file1(path, acl_type, acl, 0));

The last argument (follow) passed to acl_set_file1 is 0 and the first lines of acl_set_file1 implementation reads:

  if (follow == 0) {
/* XXX this requires some thought - can links have ACLs? */
errno = ENOTSUP;
return(-1);
}

We have the explanation of the Operation not supported error we got earlier. Note that the comment is not mine, it is actually in the libc source code!

Does it mean it is impossible to set an ACL on a symlink? Does it mean our only option is to file a bug asking some Apple engineer to think harder if links can have ACLs? Fortunately no. There is a third function in the acl_set(3) API: acl_set_fd, which acts on a file descriptor. Hopefully, getting the file descriptor of a symlink is as simple as open(path, O_SYMLINK).

That's it. With this patch, you'll be able to run ./chmod -h +a "everyone allow delete" myLink and have the ACL to be set on the symlink!

If you need to set ACLs on symlinks on a daily basis, I suggest you do not overwrite /bin/chmod but install the patched version of chmod in /usr/local/bin. Well, if you read that post till there, you probably know that already.

This bug has been reported to Apple and is known as radar #6264303 which is a duplicate of radar #5684438.

Sunday, January 04, 2009

Using your own address book in the iPhone Simulator

Jailbroken iPhone with openssh:

scp mobile@iPhone:~/Library/AddressBook/* ~/Library/Application\ Support/iPhone\ Simulator/User/Library/AddressBook

Non-jailbroken iPhone:

Say bye bye to John Appleseed & Co.

Wednesday, October 15, 2008

Kagi Registration Module (lack of) security

I'm in the process of choosing an eCommerce partner for selling my future shareware. I have narrowed down to eSellerate and Kagi as they are widely adopted by Mac shareware developers. After reading their respecting obfuscated pricing policies, I decided to have a look at what they offer for integrating the purchasing process into the application.

Kagi offers the Kagi Registration Module (KRM) which is basically a library that provides an in-application one click purchase experience. Sounds pretty good. I start reading the KRM developer documentation and stumble on the Security section:

The ZonicKRM submits orders through an SSL connection for security, however pricing information is currently passed from the application to the ZonicKRM as an XML string.

If this data is not checksummed, or otherwise protected, a malicious user may be able to edit the XML string within an application's executable and submit an order with an invalid price.

In the long term, this attack will be denied by moving the responsibility for pricing information from the KRM library to the KRM server. When this process is complete, vendors will be able to override the pricing information in shipping copies of an application using their Kagi database entry.


WHAT THE FUCK ? The user is able to choose the price he wants to pay ? Can't be true, this part of the documentation must be outdated. Guess what... it's not, long term is long term!

Note that checksumming or protecting is pure bullshit as long as the price comes from the application and not Kagi's server.

I searched for the first shareware using KRM I found, opened it with an hex editor, did search and replace of the string 30.00 to 01.00 and I indeed successfully ordered the shareware for $1.

This is totally irresponsible from Kagi. I don't know how this registration scheme could have been designed this way in the first place. No sensible person can design an ordering system where the price is set by the client.

Please don't flame me, I'm a good guy. I contacted the $30 shareware author and offered to pay the remaining $29 I owe him. I should have searched a bit longer for a cheaper shareware. $1 + $29 is a bit expensive to demonstrate that KRM sucks ;-)

The Bottom Line
Don't use KRM as long as you can't set the price of your shareware on Kagi's server.

Wednesday, September 03, 2008

QuietXcode

Have you ever noticed the Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x319a380, has non-zero refcount = 1 messages in the console ? Chris Espinosa replied about these warnings to Matt Neuburg:


The second one is an error deep in some system framework when running under Garbage Collection that we have not been able to track down yet. It simply means that somebody has neglected to do a final release on a memory block that nobody has kept a pointer to (making the final release technically impossible). The Garbage Collector knows the block is inaccessible and is freeing it, but is warning us that somebody forgot to formally release it before the pointer to it went out of scope. Bad form, but no actual harm.

I think it actually harms. These messages are filling the console so much it becomes unusable. I'm a big fan of GeekTool and I always have the tail of the console on the desktop. Now, it looks always the same and interesting messages from various applications are lost in the mass of free_garbage messages:

Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x319a380, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x31bf6e0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x3263da0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x3274eb0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x319a380, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x31bf6e0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x3263da0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x3274eb0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x201c8b0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x3256110, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x201c8b0, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x3256110, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x2045540, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x208ca10, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x2045540, has non-zero refcount = 1
Xcode(19838,0xb0103000) malloc: free_garbage: garbage ptr = 0x208ca10, has non-zero refcount = 1

So I decided to tackle the problem and here is my Solution: QuietXcode 1.1.4 (5 KB). This is an Xcode plugin that patches the culpable call to malloc_printf("free_garbage: garbage ptr = %p, has non-zero refcount = %d", ...).

You can build the plugin either by typing xcodebuild in a terminal or by building it (⌘ + B) in Xcode. Building the plugin will also automatically install it into your ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins folder.

Once it's installed, you have to relaunch Xcode. You should see the message <QuietXcode> loaded successfully in the console and no more free_garbage messages.

The plugin performs a safe patch, that is, if it does not find the expected call to malloc_printf and the expected Xcode version (greater than or equal to 3.1/1099), it logs a more or less comprehensive error to the console. Have fun browsing the source code, it demonstrates how to use the dyld and mach-o apis to locate non exported symbols and the mach api to dynamically patch code.

Note that the plugin is for i386 only, porting it to ppc and/or 64 bits is left as an exercise to the reader.

Friday, August 22, 2008

Exploring iPhone OS 2 files

Update: This technique also works with iPhone OS 3.x. You will find the VFDecrypt keys on The iPhone Wiki Firmware page. Just select the appropriate iPhone model and Version/Build of your firmware.

It turns out to be pretty simple:


  1. Download iPhone OS 2.0.2 (5C1)
    curl -O http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-5241.20080818.t5Fv3/iPhone1,2_2.0.2_5C1_Restore.ipsw

  2. Unzip the ipsw which is actually a zip file
    unzip iPhone1,2_2.0.2_5C1_Restore.ipsw

  3. Download vfdecrypt
    svn co http://iphone-elite.googlecode.com/svn/trunk iphone-elite

  4. Compile vfdecrypt
    make -C iphone-elite/vfdecrypt_win32

  5. Decrypt the dmg (key from The iPhone Wiki)
    ./iphone-elite/vfdecrypt_win32/vfdecrypt -i 018-3978-1.dmg -k 31e3ff09ff046d5237187346ee893015354d2135e3f0f39480be63dd2a18444961c2da5d -o iPhoneOS-2.0.2.dmg

  6. Mount iPhone OS dmg and start exploring
    open iPhoneOS-2.0.2.dmg

Do not buy iQuarantine X

From iQuarantine X website:


  • iQuarantine X is not a background script or a script that gets attached to files or folders.
  • iQuarantine X is the first application to make the LEOPARD FILE QUARANTINE ALERTS go away.
  • iQuarantine X is the easiest way to rid LEOPARD of all FILE QUARANTINE ALERTS.

So, if it's not a script, what is it (beside a scam) ?
It's a hack that binary patches a system framework (/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore) by short-circuiting the private function _FSAllocateQuarantineData.

So we have four good reasons not to buy it:
  1. It has an unacceptable upgrade policy.
  2. It binary patches a system framework.
  3. Developer does not reply to e-mails.
  4. You can disable the Leopard quarantine for free with an official technique.

Thursday, July 10, 2008

The missing NSLocale documentation

+ (NSArray *)preferredLanguages
Return Value
The user's language preference order as an array of NSString objects, each of which is a canonicalized IETF BCP 47 language identifier. This is defined by the user in System Preferences → International → Language.

For your information: this is stored in the gloal domain in the AppleLanguages key.

+ (id)currentLocale
Return Value
The logical locale for the current user. The locale is formed from the settings for the current user’s chosen system locale overlaid with any custom settings the user has specified in System Preferences → International → Formats.
This method may return a retained cached object.


+ (id)autoupdatingCurrentLocale
This one I have not understood how it is supposed to be used. If someone knows, please let us know in the comments.

Now, if what you want is the current language, you should not use either of these methods. Instead you should use something like NSLocalizedString(@"ISOLanguageCode", @"iso language code"). Then you have to define "ISOLanguageCode" = "en"; etc. in all your Localizable.strings files.