Launching apps on 10.13.2


Graham Cox
 

Hi all,

We are getting a few reports from a couple of our more adventurous customers who are running a beta version of 10.13.2, saying that our app doesn’t launch (the App is available on the App Store and launches fine on 10.13.1).

From the description, it seems it fails extremely early in the launch process, and gives up long before it executes main(). We are trying to get logs and so on to see if there’s anything there. Officially we don’t support unreleased OS versions, and we’re not running this ourselves, so it’s not easy to quickly check out. However if there’s something changed about launching, we want to be ready for it.

Has anyone else seen this behaviour? If so, what’s the cause and should we do anything about it?

—Graham


2551phil
 

Assuming they’re direct downloading it, are they moving it out of ~/Downloads before trying to run it?

I’ve been facing this issue myself recently. Look for

Notes: Translocated Process


in the crash log.


Best


Phil
@sqwarq

On 6 Dec 2017, at 09:44, Graham Cox <graham@...> wrote:

Hi all,

We are getting a few reports from a couple of our more adventurous customers who are running a beta version of 10.13.2, saying that our app doesn’t launch (the App is available on the App Store and launches fine on 10.13.1).

From the description, it seems it fails extremely early in the launch process, and gives up long before it executes main(). We are trying to get logs and so on to see if there’s anything there. Officially we don’t support unreleased OS versions, and we’re not running this ourselves, so it’s not easy to quickly check out. However if there’s something changed about launching, we want to be ready for it.

Has anyone else seen this behaviour? If so, what’s the cause and should we do anything about it?

—Graham





Quincey Morris
 

On Dec 5, 2017, at 18:44 , Graham Cox <graham@...> wrote:

We are getting a few reports from a couple of our more adventurous customers who are running a beta version of 10.13.2

How are you distributing the beta version? A zip file?

One problem I run into often is that customers have their email on a Windows PC, and they therefore tend to download the zip file on the PC. If they unzip it there before moving to the Mac, the app won’t run properly. It has to be unzipped on the Mac.

I don’t know of any app launching problems currently being discussed on the developer forums, but there is a discussion going on about the so-called “Month 13” bug:


which seems to represent a spurious log message. It may actually be a real bug too.

I doubt either of things will be of much help, but they’re the only issues I can think of.


Graham Cox
 

Well, 10.13.2 is out, so I now have to solve this issue urgently.

Turns out it is in my code (no real surprise) and the issue seems to be with this:

[coder decodeArrayOfObjCType:@encode(float) count:m_count at:tempPattern];

Invoking this causes an internal exception : "*** -[_NSKeyedCoderOldStyleArray initWithCoder:]: unable to decode element in array of size (4) and count (2)”

This is very old code that has always worked up until now. I can certainly rewrite this code to use something more robust - but the problem is a lot of existing data that has written an archive this way can’t be read, and that is a problem. I need a way to read it, even if it’s only to convert it to another form.

The corresponding archiving step is:

float tempPattern[8];
[coder encodeArrayOfObjCType:@encode(float) count:[self count] at:tempPattern];



It makes me wonder if @encode(float) is actually legal, or perhaps I’ve just been getting away with it for years?

Anyway, if anyone can see a way I could read the contents of such an archive, I’d be very grateful.

—Graham


Quincey Morris
 

On Dec 7, 2017, at 16:34 , Graham Cox <graham@...> wrote:

It makes me wonder if @encode(float) is actually legal, or perhaps I’ve just been getting away with it for years?

Can you find out what @encode(float) is in 10.12 and 10.13.2?

Does decoding fail if you use @encode(uint32_t) instead?


Graham Cox
 

So, this is looking damn strange. So far, it appears is if 10.13.2 has actually broken dearchiving when using this. It may be an intentional breakage, or not.

I’ve been through the documentation and it seems is though [-NSKeyedArchiver encodeArrayOfObjCType:@encode(float) …] is perfectly legal. @encode(float) basically returns the C string “f”. It looks as if 10.13 added a more secure mechanism for encoding and decoding arbitrary types - I’m wondering if somehow accommodating this new API has broken the old one.

(DISCLAIMER: I’m reluctant to point the finger at OS code when things don’t work for obvious reasons, but hear me out!)

This is a fragment of the archive that is written (complete archive attached):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>$0</key>
<real>4</real>
<key>$1</key>
<real>1</real>
<key>$2</key>
<real>1</real>
<key>$3</key>
<real>1</real>
<key>$class</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>NS.count</key>
<integer>4</integer>
<key>NS.size</key>
<integer>4</integer>
<key>NS.type</key>
<integer>102</integer>
</dict>
</plist>


This is a dictionary embedded in the archive corresponding to the use of -encodeArrayOfObjCType:

In this case I’ve written 4 float values, as can be seen in the corresponding NS.count entry. The values of the elements of the array are keyed using $0..$3. (the corresponding values are 4.0, 1.0, 1.0, 1.0)

I’m not sure how NS.type works, but its value is always 102 for these float arrays.

When NSKeyedDearchiver is asked to dearchive this array, internally it makes an object with the class _NSKeyedCoderOldStyleArray, and calls -initWithCoder: on it. That method throws the exception "*** -[_NSKeyedCoderOldStyleArray initWithCoder:]: unable to decode element in array of size (4) and count (2)” noted earlier. To try and figure out what’s going on, I’ve created a class of my own which I can substitute for this class. My class gets created and called instead as expected, and I can ask the decoder for NS.count, NS.type, NS.size, and I get back the values from the archive as expected.

But when I ask for the value of the key “$0”, it doesn’t exist. Nor do any of the others. Presumably this is what _NSKeyedCoderOldStyleArray is discovering as well, and throws the exception.

At this point it’s unclear what the further problem is - is NSKeyedArchiver disallowing the key, or is it really the case that the key doesn’t exist - I don’t know. Peeking at what data members of NSKeyedUnarchiver I can, I can’t see anything useful.

I’m going to create a simple test case that shows the problem in isolation (if it does), and submit it as a bug. I’m thinking that this particular feature of archiving is not used much, Apple have broken it, and it wasn’t picked up in testing. Again, I’m reluctant to draw this conclusion, but that’s how it looks right now.

It would be useful if someone else could check this out to confirm or disprove it though.

—Graham

On 8 Dec 2017, at 1:11 pm, Quincey Morris <quinceymorris@...> wrote:

On Dec 7, 2017, at 16:34 , Graham Cox <graham@...> wrote:

It makes me wonder if @encode(float) is actually legal, or perhaps I’ve just been getting away with it for years?
Can you find out what @encode(float) is in 10.12 and 10.13.2?

Does decoding fail if you use @encode(uint32_t) instead?


Graham Cox
 

OK, the bug is reproducible in a very simple test case. Apple have f***ed up for sure here.

This writes the simplest possible archive that includes this structure - here’s what it looks like in a plist editor:




Running this on 10.13.2 throws an exception. Earlier system versions are fine.

The code in the test app is this:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// create an archive using -encodeArrayOfObjCType:count:at: with 32-bit floats

NSString* path = [@"~/Desktop/testArchive.plist" stringByExpandingTildeInPath];

float testValues[] = {1.0, 2.0, 3.5, 4.6, 3.1415926, 0.0};

NSMutableData* testArchive = [NSMutableData data];

NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:testArchive];

[archiver encodeArrayOfObjCType:@encode(float) count:6 at:testValues];
[archiver finishEncoding];

[testArchive writeToFile:path atomically:YES];

// now read it back in and see if it can be dearchived - in 10.13.2, this will throw an exception.


NSData* readArchive = [NSData dataWithContentsOfFile:path];

NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:readArchive];

float readValues[6];

[unarchiver decodeArrayOfObjCType:@encode(float) count:6 at:readValues];
[unarchiver finishDecoding];

for( int i = 0; i < 6; ++i )
NSAssert( readValues[i] == testValues[i], @"dearchived data does not match values archived");

}

Submitting a bug report now. The annoying thing is that I can’t see any workaround. This is a killer for our users right now. Grrrr…..

On 8 Dec 2017, at 1:42 pm, Graham Cox <graham@...> wrote:

I’m going to create a simple test case that shows the problem in isolation (if it does), and submit it as a bug. I’m thinking that this particular feature of archiving is not used much, Apple have broken it, and it wasn’t picked up in testing. Again, I’m reluctant to draw this conclusion, but that’s how it looks right now.


Graham Cox
 

Bug Reporter No: 35926492

On 8 Dec 2017, at 2:06 pm, Graham Cox <graham@...> wrote:

Submitting a bug report now. The annoying thing is that I can’t see any workaround. This is a killer for our users right now. Grrrr…..


Quincey Morris
 

On Dec 7, 2017, at 19:06 , Graham Cox <graham@...> wrote:

The code in the test app is this:

FWIW, 102 is 0x66, or a lower case “f”. Also, I think a “$” at the start of an archive key is an escape character, and so probably shouldn’t be taken literally. However, I don’t know what key you’d need to ask for instead.

On to the code…

The first few times I tried this, I thought I got inconsistent results, but maybe I just did something wrong. The last several times I tried, I got the same exception as you, but only with the “float” type. All the other types I tried worked.

One odd thing I noted. If I encoded the array as anything other than float elements (e.g. specifying “@encode(double)” or “@encode(short)”), and decoded with “@encode(float)”, I got this exception message:

*** -[_NSKeyedCoderOldStyleArray decodeArrayOfObjCType:count:at:]: type ('f') or count (6) does not match stored type and count ('d', 6)

but if I encoded the array as “@encode(float)” and decoded it as anything else, I got this exception message:

*** -[_NSKeyedCoderOldStyleArray initWithCoder:]: unable to decode element in array of size (4) and count (6)

It’s very odd.



Graham Cox
 

On 8 Dec 2017, at 4:05 pm, Quincey Morris <quinceymorris@...> wrote:

On Dec 7, 2017, at 19:06 , Graham Cox <graham@...> wrote:

The code in the test app is this:
FWIW, 102 is 0x66, or a lower case “f”.
Ah, makes sense.


Also, I think a “$” at the start of an archive key is an escape character, and so probably shouldn’t be taken literally. However, I don’t know what key you’d need to ask for instead.
I wondered about that myself. I tried just leaving it off, but that didn’t work either. Without the source code for the private ‘old array’ class, it’s hard to guess what to try.




On to the code…

The first few times I tried this, I thought I got inconsistent results, but maybe I just did something wrong. The last several times I tried, I got the same exception as you, but only with the “float” type. All the other types I tried worked.

I think it must have fallen through the one crack in the testing. I’d hate to think they didn’t test it at all… ;-)


One odd thing I noted. If I encoded the array as anything other than float elements (e.g. specifying “@encode(double)” or “@encode(short)”), and decoded with “@encode(float)”, I got this exception message:

*** -[_NSKeyedCoderOldStyleArray decodeArrayOfObjCType:count:at:]: type ('f') or count (6) does not match stored type and count ('d', 6)
but if I encoded the array as “@encode(float)” and decoded it as anything else, I got this exception message:

*** -[_NSKeyedCoderOldStyleArray initWithCoder:]: unable to decode element in array of size (4) and count (6)
It’s very odd.
Indeed. We’ve raised a DTS support incident so that it gets looked at quickly - I would imagine if the bug really is there, we can’t be the only ones screaming about this - unreadable archives with no workaround is quite serious.

—Graham


Quincey Morris
 

On Dec 7, 2017, at 21:44 , Graham Cox <graham@...> wrote:

unreadable archives with no workaround is quite serious

It’s actually quite an unusual scenario, I finally realized:

a. You’re archiving something in a keyed archive without a key.

b. You’re archiving using an API that I doubt is used at all very often. (Also, the non-array version of the …ObjCType API is deprecated.)


Graham Cox
 

On 8 Dec 2017, at 4:52 pm, Quincey Morris <quinceymorris@...> wrote:

On Dec 7, 2017, at 21:44 , Graham Cox <graham@...> wrote:

unreadable archives with no workaround is quite serious
It’s actually quite an unusual scenario, I finally realized:

a. You’re archiving something in a keyed archive without a key.

b. You’re archiving using an API that I doubt is used at all very often. (Also, the non-array version of the …ObjCType API is deprecated.)
Very true - as I mentioned it's very old code that hasn’t been revisited in along time. Nevertheless, it’s not deprecated, and has always worked previously. I’ve never found anything in documentation that suggests it’s not something that should be used. I’m certainly willing to update my code to use something more robust in future, but that still leaves the problem of reading the existing archives.

—Graham