The Universal Binary of Crashiness

June 9th, 2008 by Joe Ranieri

What would you say to an application that crashes Finder to the point of being useless? One that merely has to be downloaded, and not even run? I present NukeApp.

For those who don’t feel like experiencing this firsthand, the behavior will vary depending on your Safari download settings. If you’ve set it automatically open downloaded files, Safari will crash and the world will be happy. If you have that option turned off, and you open the zip file up in Finder, Finder will enter a crash loop.

View a movie of the experience.


So, on to the technical details. I’ll start off by saying that this binary has been specifically crafted and is not a valid universal binary — it lies horribly about the number of architectures it contains.

Let’s take a look at the stack trace for where it dies (only showing the top few frames):

_LSAddExecutableFormatInfo
_LSAddBundleExecutableInfo
_LSRegisterDirectoryNode
_LSFindOrRegisterBundleNode
_LSCopyInfoForNode
_LSCopyItemInfoForRefInfo

Aha, it’s LaunchServices giving us the trouble! It looks like Finder is asking it for information about the application and LaunchServices is registering the application in its database. From the looks of it, it’s trying to determine the format of the executable. A closer look at the top function reveals that it’s opening the file and reading it in:

movl        0xfffffb08(%ebp),%eax
leal        0xfffffd34(%ebp),%edx
movl        $0x00000200,0x08(%esp)
movl        %edx,0xfffffafc(%ebp)
movl        %edx,0x04(%esp)
movl        %eax,(%esp)
calll       read$UNIX2003

You’ll notice it’s only reading 512 (0×200) bytes. A bit after this it checks the first long in the data to see which type of executable it is - Mach-O, Mach-O 64-bit, PEF, or a fat binary. If we go down the function a bit more, you’ll notice there’s some strings for each arch type (ppc, ppc64, i386, x86_64). So, what it must be doing is looping through each fat_arch that follows the fat_header. However, since we’re getting crashes, it must not be making sure that it stops reading at the end of its buffer.

Here’s an example that suffers the same issue (ignoring endian issues):

int file = open("/path/to/binary")
char buffer[512];
 
read(buffer, sizeof(buffer), file);
 
fat_header *header = buffer;
fat_arch *archs = buffer + sizeof(fat_header);
 
for(int i = 0; i < header->nfat_archs; i++) {
	// do something with archs[i]
}

This situation comes up in a few diferent places… so how do they handle it?:

  • CFBundle restricts nfat_archs count to the most that fits in the buffer
  • the kernel loader returns error if the archs exceed the size of its buffer (one page size)

I’ll also note that this is not exploitable (it ONLY reads 512 bytes into a 512 byte buffer) and occurs in every version of OS X we could lay our hands on (10.4, 10.5, etc). You cannot inject code into Finder, the Dock, or any other process that crashes in this routine. It’s simply a crash.

We reported this to Apple February 28th (radar 5771210), and have received no response.


Post updated June 9th, with video and slightly better explanation.


And we’re back

May 6th, 2008 by Ryan Govostes

Sorry to those who tried to visit us this morning, we had a little bit of downtime. Thankfully, things seem to be functional again.

Admittedly, things have been quiet on our end of the wire these last few weeks. I’ll see if I can use a cattle prod to coax the others into posting what they’ve been up to.

As for me, I’m finishing up my last two final exams here at Rensselaer Polytechnic Institute, and I plan on spending some time in the coming weeks getting comfortable with iPhone OS development and back into the groove of coding for OS X. Last year, Jon, Joe, and I shot ideas back and forth for some consumer products, so I think I’ll go over the list and see what’s worth fleshing out.


Wyoming, Michigan, you’re not alone (cities named after states)

April 9th, 2008 by Jonathan Johnson

I ordered some new sandals online this weekend, and they shipped last night from Wyoming, Michigan. Cities named like this confuse me, and I felt prompted to figure out what other cities are named after states. After doing some quick searches, I couldn’t find a full list, and decided it would be a fun little problem to solve.

So I coded it up really quickly. It turns out there’s a lot — 289 to be exact. Click through to the full post to see the complete list.

This list doesn’t include cities that are named after countries or foreign cities. For example, another common shipping origin seems to be Ontario, CA (California, not Canada). That one confused me even more when I first read it on my tracking information.

Read the rest of this entry »


A Bit of RB Trivia: The Answer

April 4th, 2008 by Joe Ranieri

So, the question I asked last time was this:
Name a situation when the global App object is nil (while executing user code).

The two answers that were submitted and correct are:

  • Charles Yeomans pointed out that properties in modules are destructed after the global App object has been set to nil. Example project.
  • Ben Johnson went the other way around and noticed that the global App object is nil in your Application subclass’ constructor. Example project.

However, neither of these were the answer I was looking for. What happens is that REALbasic does a bit of initialization before setting the global App object. Part of that initialization is setting up the menubar, which entails creating the MenuItems. If you have a subclass of MenuItem in that menubar, REALbasic invokes your constructor, and at that point, the global App object is nil. Example project.

Congratulations to Charles and Ben, both of which will be receiving a free license to CalendarKit.


A Bit of RB Trivia

March 31st, 2008 by Joe Ranieri

There’s a free license to CalendarKit 2 to the first person who can answer this question:

Name a situation when the global App object is nil (while executing user code).

* Offer not applicable to Norman Palardy or past or present REAL Software employees.

Update: We have posted the answers.


Demangling C++ Names

March 26th, 2008 by Joe Ranieri

RuntimeException.stack is one of the most useful things to be added to REALbasic. However, we can make it a bit better by demangling any C++ function names that might be in the stack trace.

Function CPPDemangle(name as string) As string
  //! Demangles a C++ function name. Returns an empty string on failure.
  //! Only works on Mac OS X.
 
  #if targetMacOS
      declare function __cxa_demangle lib "/usr/lib/libstdc++.6.dylib" ( name as CString, _
      outBuffer as ptr, outLength as ptr, byref outState as integer ) as CString
    declare sub free lib "System" ( value as CString )
    const kStateSuccess = 0
 
    dim state as integer
    dim demangledString as CString = __cxa_demangle( name, nil, nil, state )
 
    if state = kStateSuccess then
      // create our RB string, then free the string demangle gave us
      dim result as string = demangledString
      free( demangledString )
 
      return result
    end if
  #endif
End Function

Then you can apply this function to the exception’s stack like so:

Function GetErrorStack(err as RuntimeException) As string()
  //! Gets the stack trace for our exception. This differs from
 //! RuntimeException.stack in that it demangles C++ names.
 
  // this can crash in some cases, giving us a completely useless crash log
  // <rb-feedback://keeqghwg>, hopefully this will be fixed someday...
  dim stack() as string = err.stack
  dim cleanedStack() as string
 
  // the order of RB's "for each" isn't defined <rb-feedback://hdcdbgfi>, so we have
  // to use a normal loop
  for i as integer = 0 to stack.ubound
    dim name as string = stack( i )
    dim demangledName as string = cppDemangle( name )
 
    if demangledName <> "" then
      cleanedStack.append( demangledName )
    else
      cleanedStack.append( name )
    end if
  next
 
  return cleanedStack
End Function

So, instead of seeing “__ZN14RuntimeListbox7GetTextE15getTextSelectorll” in an exception trace, you will see “RuntimeListbox::GetText(getTextSelector, long, long)“. Much, much easier on the eyes. :)


CalendarKit 2.0 beta, integrates with Outlook on Windows

March 24th, 2008 by Alacatia Labs, Inc.

We are pleased to announce a beta of CalendarKit 2.0! The major new feature in this release is support for Outlook calendars under Microsoft Windows. Without any code changes, existing REALbasic applications using CalendarKit are now able to manipulate calendars on both Mac OS X 10.5 “Leopard” and Microsoft Windows.

The only known issue is that notifications of external changes to calendars are not yet working. We will address this in an update in the near future.

If you have purchased CalendarKit, your account page will give you the option of downloading the latest version. If you are interested in learning more about CalendarKit and what it can bring to your applications, please visit http://alacatialabs.com/products/calendarkit/ and download a demo.


Programatically Controlling Spaces

March 22nd, 2008 by Joe Ranieri

There’s been a lot of questions on mailing lists about how to control Spaces programatically. So far, there’s been no results from these discussions. Well, fortunately accomplishing this is quite simple, if you’re comfortable using private APIs.

Functions to query the current settings:

CGError CGSGetWorkspace(CGSConnectionID cid, CGSWorkspaceID *outWorkspace);
extern bool CoreDockGetWorkspacesEnabled();
extern void CoreDockGetWorkspacesCount(int *rows, int *columns);

You’ll probably also want to switch spaces. You can accomplish this by using a distributed notification. This tells the Dock to switch spaces, giving you all of the normal animations:

- (void)switchToSpace:(CGSWorkspaceID)spaceNumber {
  // note that the notification is 1 based, but CGSWorkspaceID is zero based!
  [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.switchSpaces"
                                                                 object:[NSString stringWithFormat:@"%i", spaceNumber + 1]];
}

And lastly, you’ll probably want to get notified when things change:

//! Gets called when the current space changes.
void SpaceChangedCallback(CGSNotificationType type, CGSWorkspaceID *workspace, unsigned int dataLength, Controller *self) {
  if(*workspace != kCGSTransitioningWorkspaceID) {
    // do something
  }
}
 
//! Gets called when the user enables or disables Spaces.
- (void)spacesEnabledChanged:(NSNotification *)notification {
  // do something
}
 
//! Start listening for workspace related changes.
- (void)registerForNotifications {
  // listen for when Spaces is enabled or disabled
  [[NSDistributedNotificationCenter defaultCenter] addObserver:self
                                                      selector:@selector(spacesEnabledChanged:)
                                                          name:@"SpacesEnableChange"
                                                        object:nil
                                            suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
 
  // listen for when the current space changes
  CGSRegisterNotifyProc((CGSNotifyProcPtr)SpaceChangedCallback, kCGSNotificationWorkspaceChanged, self);
}

You can find a full code example in the CGSInternal svn repository under Examples/SpacesSwitchingMenu, which mimics the Spaces menu extra.

Happy hacking!


Review of Vista SP 1

March 19th, 2008 by Ryan Govostes

The Internets are abuzz with the news that Microsoft has finally released the first service pack to its widely successful Windows Vista, just one year (plus change) after it first hit retail store shelves.

As a user of Windows Vista Ultimate, I watched the service pack through its beta period with interest. As I’ve mentioned before, Windows and I don’t always see eye-to-eye, so I decided it best to refrain from installing an unstable, pre-release quality operating system on my production machine — a MacBook Pro.

So, I grabbed the Service Pack 1 updater from Microsoft. Weighing in at over 400 MB, the download took roughly an hour to complete. I giddily started the installation at a quarter past 11 PM; after a few reboots during the install process, I was greeted with a fresh view of Windows:

It isn’t often that a 255 by 139 pixel screenshot conveys so many layers of information. Your eye might first be drawn to the third line of text, suggesting that I have pirated Windows. Not so — in fact, my cell phone shows that I placed a 6 minute, 17 second call to Microsoft’s activation center at 8:50 PM, when I activated Windows for the nth time. The update seems to have deactivated my install; I haven’t tried to activate for the (n + 1)th time to see if it will work.

Second, you might notice that the time is 3:06 AM. That’s right — it took four hours to get me back into Windows. Consider that a fresh Windows Vista install takes around 45 minutes (if I remember correctly); OS X takes around 20. Never mind why I’m up at 3 AM on a school night, four hours is a ridiculous amount of time for a system update.

Third, the well-informed reader will note that the build number in the screenshot, 6000, does not match the build number of Windows Vista SP 1, which is 6001. That’s right. After four excruciating hours, the install failed — with no particularly informative error message. I can’t find the exact error number in my Windows logs, but there are thousands of entries at 3:01:37, all reading

Windows Servicing failed to complete the process of setting package
Package_82_for_KB936330~31bf3856ad364e35~x86~~6.0.1.18000 () into Staged(Staged) state

Finally, we note that the screenshot has a hideous red outline. I couldn’t figure out how the equivalent of print screen on my MacBook Pro keyboard, so I used the “Snipping Tool.”


Not sure of the point of allowing signups then…

March 14th, 2008 by Jonathan Johnson

I received this email a few minutes ago:

Dear Registered iPhone Developer,

Thank you for expressing interest in the iPhone Developer Program. We have received your enrollment request. As this time, the iPhone Developer Program is available to a limited number of developers and we plan to expand during the beta period. We will contact you again regarding your enrollment status at the appropriate time.

It seems to me if they were only opening it up to select people, they should have held off on the signup form until they were actually ready for people to sign up. I guess they have to wait to get our $99.

Update:
It sounds like it was either first-come or random. I guess we fail for now.