Friday, June 4, 2010

Not a real boy

Of all mobile software platforms, I have extensive development experience with three: Windows Mobile, BlackBerry and iPhone. For all three, there's a simulator for ease of debugging. And here's my expert opinion: the Microsoft Device Emulator is the best. The BB simulator does not support multiple debugging sessions in a row - if you change and recompile, you have to restart the simulator, and that takes a nontrivial amount of time. The iPhone simulator is not that bad, but it has considerable differences with the real device. Also, you cannot run arbitrary software on it - the simulator does not actually simulate the ARM CPU of a real iPhone, it runs compiled Intel code.

Microsoft Device Emulator, on the other hand, emulates ARM instruction set to a tee, supports debugger reconnection, and on top of that, approximates real device performance reasonably well. Hats off to MSFT. Apple Computer and RIM - you officially suck.

Monday, March 29, 2010

Bug-o-rama, encore...

Another day, another beautiful C++ bug. My program is a shareware Windows Mobile application. And it uses a unique device ID for the purposes of licensing and user identification. On newer devices (iPhone, Blackberry, WinMobile 5+) such a DeviceID is readily available. On older WM devices, however, it was an optional feature. I have several fallback mechanisms, the most basic of those would hash together several system-provided data structures (CPU info, OS version, etc.) and use the hash value as a DeviceID. This schema is somewhat open to collisions, but such devices are rare, so I'm not worried much about those. A false negative is worse. And I had a case of a device where such false negatives were happening all the time. You retrieve a (hash-based) DeviceID, store it, on the next run it's different.

Here's the deal. One of the sources for the hash was the PROCESSOR_INFO structure that the OS kernel (or maybe the OAL) readily provides. The structure consists of some DWORD's and some wide (wchar_t) strings:

typedef struct {
WORD wVersion;
WCHAR szProcessorCore[40];
WORD wCoreRevision;
WCHAR szProcessorName[40];
WORD wProcessorRevision;
WCHAR szCatalogNumber[100];
WCHAR szVendor[100];
DWORD dwInstructionSet;
DWORD dwClockSpeed;

If you look closely, you'll see that the data size all the way up to szVendor is 566 bytes - not a multiple of 4. And DWORDs have to be aligned on 4-byte boundary. So the in-memory layout of the structure includes two bytes of padding between szVendor and dwInstructionSet. And it happened so that on this particular device, the value of those two bytes would vary from call to call. So the hash was different, so the DeviceID would vary from run to run.

One would expect a straightforward implementation of IOCTL_PROCESSOR_INFORMATION to keep a copy of the struct somewhere in ROM, and memcpy() it into userspace on demand. Not on this device, though...

Once I'd zero out the padding, the app would perform as advertised. And there was, as they say, much rejoicing. Later on, I've encountered other bugs on this antiquated device, but that's a whole another story.