NSBundle woes

The iOS XScreenSaver port is basically done, except for the minor detail that it won't run outside of Xcode. If I run it under Xcode targeted at my devices, I can run it perfectly on my iPhone or iPad. But then I hit "stop" in Xcode, and launch that same app manually on the device, and it gets a SEGV as soon as it tries to load one of the bundles inside the app:

strcmp + 0
ImageLoaderMachO::parseLoadCmds() + 54
ImageLoaderMachOCompressed::instantiateFromFile(...) + 296
ImageLoaderMachO::instantiateFromFile(...) + 302
_ZN4dyldL10loadPhase6EiRK4statPKcRKNS_11LoadContextE + 478
_ZN4dyldL14loadPhase5statEPKcRKNS_11LoadContextEP4statPiPbPSt6vectorIS1_SaIS1_EE + 386
_ZN4dyldL10loadPhase5EPKcS1_RKNS_11LoadContextEPSt6vectorIS1_SaIS1_EE + 278
_ZN4dyldL10loadPhase4EPKcS1_RKNS_11LoadContextEPSt6vectorIS1_SaIS1_EE + 218
_ZN4dyldL10loadPhase3EPKcS1_RKNS_11LoadContextEPSt6vectorIS1_SaIS1_EE + 1144
_ZN4dyldL10loadPhase1EPKcS1_RKNS_11LoadContextEPSt6vectorIS1_SaIS1_EE + 108
_ZN4dyldL10loadPhase0EPKcS1_RKNS_11LoadContextEPSt6vectorIS1_SaIS1_EE + 262
dyld::load(char const*, dyld::LoadContext const&) + 224
dlopen + 742
dlopen + 42
_CFBundleDlfcnLoadBundle + 106
_CFBundleLoadExecutableAndReturnError + 370
-[NSBundle loadAndReturnError:] + 904
-[NSBundle load] + 16
-[NSBundle principalClass] + 40

That's my call to [NSBundle principalClass]. The bundle exists; I see the pathname it's loading, and it's the same one it was successfully loading and executing under Xcode, on this same hardware.

I'm pretty stumped on how to solve this one. There's nothing like a Heisenbug that depends on whether the debugger is running.

I've turned on the various malloc environment variables inside Xcode and saw nothing. (Not surprising, though; that trick never works.)

Tags: , , , ,
Current Music: EMA -- Marked ♬

12 Responses:

  1. Cobbal says:

    Can't load dynamic libraries on iOS; when attached to an XCode debugging session though, it lets you load them (probably so the debugger can generate code). I just ran into this a few days ago.

    • jwz says:

      Do you see any evidence of this in the documentation? Because I see this shiny principalClass method right there in the iOS API. Why would that exist at all?

      Also, strcmp(0,0) is a great error message.

      • Cobbal says:

        I don't have evidence, but I believe the code signing is the issue there. A piece of code has to have a valid signature to be paged in with the executable bit, and frameworks are just copied into the resource bundle directly without the bundles themselves being signed.

        You could try manually signing the bundles with the codesign executable ("codesign -s bundlename") although I haven't tried it and suspect it won't work (as Apple tends to be less than friendly and flexible about such things)

        I suspect the principalClass method exists either just for the application bundle, or because they forgot to remove it when porting from OS X.

        I would, of course, love to be proved wrong about all this, but this is what I've found when working with it.

      • chpwn says:

        No, you can't: for no other reason than the App Store signing only works on one executable.

        On iOS, all user libraries must be statically linked. No exceptions.

      • p says:

        They put a little note in their "Bundle Programming Guide":

        Note: The creation and use of loadable bundles is not supported in iOS.

        • jwz says:

          Well, isn't that just a steaming load of shit.

          The bundles are being loaded from inside my .app bundle, so all of those bits were signed. It's impossible to modify them. If there's an exploit there that this is preventing, I'd love to hear about it.

          I guess this is now going to turn into a 13MB monolithic app, instead of a 400K app that loads and unloads ~60K modules one at a time. God dammit.

          • If it totals 13MB of code either way, there shouldn't be any impact on performance since the VM system will only fault in the executable pages that are used, with a granularity of 4k.

          • Frode M says:

            Someone else blogged about a similar problem trying to port over LaTeX: http://vallettaventures.com/post/13124883568/the-price-of-a-messy-codebase-no-latex-for-the-ipad

            • Bill Paul says:

              Oh yeah. LaTeX. In another life, I had to support LaTeX on 5 different UNIXes all at once (Solaris, SunOS 4, HP-UX, IRIX, AIX) all with a common font directory that was shared over NFS. Conventional wisdom says installed application directories should be read/execute only so that the lusers don't scribble in them, right? But screw conventional wisdom, let's break all that by having TeX generate fonts ON THE FLY when a user runs it.

              I'm glad that life is over.

              • Mike Marion says:

                I actually installed and semi-support tex across at least a few different linux and solaris installs using one path (in AFS though, so the Read-only bit is simple) using texlive. I threw in a crappy shell wrapper that each of the program names is linked to that essentially does another step of settings PATH to /big/long/path/texlive2007/bin/$arch-$os then runs the actual program from there. Sadly, even with the @sys magic of AFS, I still had to hack those bits in.

                Ugly, but it works. Or did.. could be broken and nobody cares anymore for all I know.

                Oh, and I think I ran into the same "generate the fonts on the fly" thing and solved that by putting in a step at the start of the wrapper that looks for these .fmt files that the install put in my homedir when I installed it (without telling me) and if missing, does a few mkdirs for the users and copies the files from the tool path.

                Sadly, I went through that entire exercise to drop in a "Universal" pdftex (or ps2pdf or whatever it was), that's all the users really cared about.

          • At 400K, that would literally be the smallest app on my iPhone or iPad. The largest is 1.2GB. I offer that 13MB really isn't that egregious.

  2. jwz says:

    I sure do end up hand-editing my .xcodeproj/project.pbxproj file a lot.

    Xcode can be a pain in the ass, but at least they had the good sense to use XML...