*(char*)0x08 = 1; // Say what?

Discussion in 'Mac Programming' started by zeppenwolf, Dec 21, 2014.

  1. zeppenwolf macrumors regular

    zeppenwolf

    Joined:
    Nov 17, 2009
    #1
    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.
     
  2. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #2
    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
     
  3. zeppenwolf thread starter macrumors regular

    zeppenwolf

    Joined:
    Nov 17, 2009
    #3
    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.
     
  4. subsonix, Dec 21, 2014
    Last edited: Dec 21, 2014

    subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #4
    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;
    
    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.
     
  5. jon3543 macrumors 6502

    Joined:
    Sep 13, 2010
    #5
    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.
     
  6. JustMartin macrumors 6502a

    Joined:
    Feb 28, 2012
    Location:
    UK
    #6
    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.
     
  7. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #7
    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.
     
  8. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #8
    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
     
  9. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #9
    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.

    Yep, tried that yesterday and it worked.
     
  10. Senor Cuete macrumors regular

    Joined:
    Nov 9, 2011
  11. zeppenwolf thread starter macrumors regular

    zeppenwolf

    Joined:
    Nov 17, 2009
    #11
    Ha! Hey, that works fine.

    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.
     
  12. LV426 macrumors 6502a

    Joined:
    Jan 22, 2013
    #12
    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.
     
  13. jon3543 macrumors 6502

    Joined:
    Sep 13, 2010
    #13
    Pfft. All problems can be solved with an additional level of indirection.
     
  14. hokan macrumors member

    Joined:
    Mar 18, 2014
    Location:
    Sweden
    #14
    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.
     
  15. jon3543 macrumors 6502

    Joined:
    Sep 13, 2010
    #15
    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.
     
  16. Sciuriware, Dec 23, 2014
    Last edited: Dec 24, 2014
  17. dmi, Dec 24, 2014
    Last edited: Dec 24, 2014

    dmi macrumors regular

    Joined:
    Dec 21, 2010
    #17
    No, 8 hex = 10 octal.
     
  18. Sciuriware macrumors regular

    Sciuriware

    Joined:
    Jan 4, 2014
    Location:
    Gelderland
    #18
    Auch! It must be the time of year. Of course 0x0A = 10.
    Sorry.
     
  19. hokan macrumors member

    Joined:
    Mar 18, 2014
    Location:
    Sweden
    #19
    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.
     
  20. Senor Cuete macrumors regular

    Joined:
    Nov 9, 2011
    #20
    OK so you could #include <errno.h>

    and exit(errno);
     
  21. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #21
    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).
     
  22. jon3543 macrumors 6502

    Joined:
    Sep 13, 2010
    #22
    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
     
  23. LV426 macrumors 6502a

    Joined:
    Jan 22, 2013
    #23
    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.
     
  24. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #24
    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.
     

Share This Page