Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

zeppenwolf

macrumors regular
Original poster
Nov 17, 2009
129
3
I downloaded some AppleSample code, which contained an "ExceptionReporting" project, the purpose of which is to show how to throw and display to the user NSExceptions.

If you click the button to throw a made-up exception, then a familiar looking dialog pops up showing a backtrace, saying "something really bad happened", and it gives you the option to continue in a funky state or to crash immediately.

If you choose to crash, then the following function is called:
Code:
static void CrashMyApplication() {
    *(char *)0x08 = 1;
}

Talk about "undocumented" ?!! I'm just curious what the heck that line is doing, or how it's doing it... I mean, how does that line equate to CrashMeNow(). Thx.
 
Code:
static void CrashMyApplication() {
    *(char *)0x08 = 1;
}

Talk about "undocumented" ?!! I'm just curious what the heck that line is doing, or how it's doing it... I mean, how does that line equate to CrashMeNow(). Thx.

It takes the integer 8 then convinces the compiler that it's really a character pointer, ie a pointer, pointing to the address 8. It then dereferences that address, giving a supposed char, then assign 1 to that char. The problem is that there is no char at address 8, so the application crashes.

Code:
// cast to char pointer
(char *)0x08

// dereference
*(char *)0x08

If you look at the resulting crash log you'll see:

Code:
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000008
 
Well, thanks, I get what you are saying, mostly; I understand the "mechanics" of the line, you might say, and I see what you mean that the code deliberately causes a BAD_ACCESS, but still...

You say "there is no char at address 8", well, why not? It seems like a perfectly nice place for a char... Is it about "alignment" ? If so, then, ok, it's above my knowledge base, although I still have to wonder why "8" instead of anything else. Why not "1" ? Or "7" ? Seven would have been more believable, somehow.

But also, more to the point, I wonder why this is the method chosen to exit the app. Doesn't it seem like there should be something more... natural? Something that looks more like 'exec kill -self' or something.
 
Well, thanks, I get what you are saying, mostly; I understand the "mechanics" of the line, you might say, and I see what you mean that the code deliberately causes a BAD_ACCESS, but still...

You say "there is no char at address 8", well, why not? It seems like a perfectly nice place for a char... Is it about "alignment" ? If so, then, ok, it's above my knowledge base, although I still have to wonder why "8" instead of anything else. Why not "1" ? Or "7" ? Seven would have been more believable, somehow.

The result is the same if you dereference and assign a value to an uninitialized pointer, here it's guaranteed to point to a bogus address though, 7 or 1 would also have worked.

Code:
char *p
*p = 1;

But also, more to the point, I wonder why this is the method chosen to exit the app. Doesn't it seem like there should be something more... natural? Something that looks more like 'exec kill -self' or something.

Edit: but the point is not to exit the app, but to deliberately cause a crash. I don't think too much thought went into this, just assigning a value to an invalid address.
 
Last edited:
I'm just curious what the heck that line is doing, or how it's doing it... I mean, how does that line equate to CrashMeNow(). Thx.

Google "MMU" and read the Wiki article on the subject. In a nutshell, the line tries to access memory to which you don't have access, and the CPU generates an exception.
 
But also, more to the point, I wonder why this is the method chosen to exit the app. Doesn't it seem like there should be something more... natural? Something that looks more like 'exec kill -self' or something.

Suspect this was chosen because it's the quickest way of killing a process without involving any intermediary steps or calls. When you attempt to write to a protected (or invalid) memory address, the CPU automatically kills your process.

I first saw this technique used many years ago in a hypercard like application which essentially involved code that could self modify and auto-saving. Basically, if anything went wrong the developers decided the best thing would be to bail as quickly as possible before anything could corrupt the stack.
 
You say "there is no char at address 8", well, why not?

Because the OS X operating system doesn't allow it, and modern CPUs have hardware (MMU, TLB, etc.) that can detect whether your app is trying to access memory addresses that the OS isn't allowing the app to touch. Addresses near zero are usually prohibited to prevent buggy apps from continuing to run.

But vintage CPUs, such as the 6502 used in the Apple II and MC68000 used in the Mac 128K, did allow programs to access low addresses.
 
... Something that looks more like 'exec kill -self' or something.

I'm pretty sure the program could send itself a signal using the kill(2) C function.
Code:
man 2 kill
man 2 sigaction
The signal sent should be one whose default action (as listed in sigaction) is "create core image".

The C function abort(3) is also available:
Code:
man 3 abort
 
Additionally and related, OS X uses virtual memory so the addresses doesn't correspond to real physical addresses. The same address space is used in all processes and it's possible to allocate more memory than the installed RAM. A memory segment may be read only, reserved for the stack or heap for example. In the end non of this matters much to an application developer though as long as you only use pointers that reference actual objects in memory you're good.

I'm pretty sure the program could send itself a signal using the kill(2) C function.

Yep, tried that yesterday and it worked.
 
You could always exit(0);

Ha! Hey, that works fine.

Program ended with exit code: 0

And furthermore it more directly achieves what the user expects / wants when they choose "crash": they obviously don't literally and specifically need it to "crash", the way we've been discussing it, they just want the thing to cease to exist.
 
Ugh! Pointers – and pointers to pointers – are so horrible.

Most of my programming is done in C# so there's little opportunity for me to fall into traps like this. And little need, actually. It's all a bit too low-level for my liking.
 
Ugh! Pointers – and pointers to pointers – are so horrible.

Most of my programming is done in C# so there's little opportunity for me to fall into traps like this. And little need, actually. It's all a bit too low-level for my liking.

Pfft. All problems can be solved with an additional level of indirection.
 
To be a bit nit-picky both exit(0) or returning 0 from the main() function (in a C/C++/Obj-C program) does the same thing, i.e. it signals that the program terminated without issues.
Positive numbers, on the other hand are error codes that indicate why the program terminated prematurely. These error codes aren't typically of interest for UI applications but are useful when writing things like shell scripts.
 
To be a bit nit-picky both exit(0) or returning 0 from the main() function (in a C/C++/Obj-C program) does the same thing, i.e. it signals that the program terminated without issues.

Not quite the same thing in C++, at least. Returning from main() implies control has returned to main(), which means the stack has been unwound and destructors run on local objects with automatic storage duration. Calling exit() skips the stack unwinding. If those destructors have persistent side-effects, like deleting a temporary file or something, calling exit() will bypass all that. A cleaner exit() can be implemented with exceptions.
 
Not quite the same thing in C++, at least. Returning from main() implies control has returned to main(), which means the stack has been unwound and destructors run on local objects with automatic storage duration. Calling exit() skips the stack unwinding. If those destructors have persistent side-effects, like deleting a temporary file or something, calling exit() will bypass all that. A cleaner exit() can be implemented with exceptions.

Fair enough, I was kind of assuming that the developer did the expected cleanup before calling exit(0) or that the program was only holding on to resources like memory, file descriptors ... that the OS will clean up when the process terminates.
 
To be a bit nit-picky both exit(0) or returning 0 from the main() function (in a C/C++/Obj-C program) does the same thing, i.e. it signals that the program terminated without issues.
Positive numbers, on the other hand are error codes that indicate why the program terminated prematurely. These error codes aren't typically of interest for UI applications but are useful when writing things like shell scripts.

OK so you could #include <errno.h>

and exit(errno);
 
Ugh! Pointers – and pointers to pointers – are so horrible.

Most of my programming is done in C# so there's little opportunity for me to fall into traps like this. And little need, actually. It's all a bit too low-level for my liking.

Only people who know how to do low-level programming have close to any idea what their hardware and code are actually doing. You've just moved the potential traps to different places.

exit(0) won't trap to the debugger, and real programmers know how to debug (from core dumps if necessary).
 
OK so you could #include <errno.h>

and exit(errno);

No.

For one, there are only a couple of standard values and typically dozens of non-standard ones that differ from implementation to implementation. A program should define its own exit codes that will be meaningful to the user. For another, standard functions that aren't documented to use errno can change it to any non-zero value for any reason.

There are two correct ways to use errno, and both apply only to functions documented to alter errno:

1. Function defined to set errno if it fails, e.g. ftell

if (function failed) consult errno

2. Function defined to use errno that doesn't return a distinct error code, e.g. strtol (N.B. what I show below is not a complete error-checking solution for strtol):

errno = 0;
call function
if (errno != 0) deal with it
 
Only people who know how to do low-level programming have close to any idea what their hardware and code are actually doing. You've just moved the potential traps to different places.

exit(0) won't trap to the debugger, and real programmers know how to debug (from core dumps if necessary).

What do you mean by 'actually doing'? I've programmed in the past at assembly level and - much lower - at the microcode level. Is this kind of programming relevant to the vast majority of coders these days? No, it is not. Modern compilers do a very good job of producing assembler instructions or - increasingly the case - machine-agnostic bytecode.

In the extremely rare instances where my running code has resulted in a core dump, it has always been the result of an OS or framework error, without exception. Any debugging I need to do is at a far higher level than machine code.
 
I've programmed in the past at assembly level and - much lower - at the microcode level. Is this kind of programming relevant to the vast majority of coders these days?

And the reason you can answer this question is you have experience and know how it works at this lower level. Many others just repeat (monkey imitate) the answer as heresay, without any real idea if the methodology fad of the week is useful or not.

I've interviewed tons of candidates for advanced R&D positions: the vast majority of resume submitters can't code their way out of a paper bag.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.