Thread: What happens in the operating system when we dereference a NULL pointer in C?

  1. #1
    Banned
    Join Date
    Oct 2022
    Posts
    7

    What happens in the operating system when we dereference a NULL pointer in C?

    Assume we have a reference and we initialise it with NULL.
    Code:
    int* ptr = NULL;
    *ptr = 10;
    The application will now fail since ptr does not point to any address and we are giving a value to it, which is an invalid access. So, what happens inside in the operating system? Is there a page-fault or a segmentation-fault? Will the kernel even look through the page table? Or did the crash happen before that?

    I know I wouldn't perform something like this in any software, but I'm curious what occurs internally in the OS or compiler in such a circumstance. It's also not a duplicate inquiry.

    It is platform and compiler dependant, according to this page from <<crapware site>>. The NULL pointer might be implemented by utilising a NULL page, resulting in a page fault, or it could be below the segment limit for an expand-down segment, resulting in a segmentation fault. Is that correct?
    Last edited by Salem; 01-17-2023 at 01:56 PM. Reason: Removed bogus URL

  2. #2
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    This is a little bit hard to explain, but, in essence, in systems where a fraction of memory is mapped to a process (see paging and segmentation in protected mode for Intel processors as examples), the processor implements an interrupt routine which deals if "faults". Again, as an example using Intel x86 family processors, the first 32 interruptions are reserved to the processor use. The 14th interruption (interrupt 13) is called GENERAL PROTECTION FAULT (GPF), that happens if you are trying to access memory not mapped to your process (a segment has a base address and limit... and there is paging as well)... When an address is used to access memory that it is not mapped to your process, the GPF interruption occurs, giving a chance to the kernel to do something about it.

    On Unix systems a GPF will generate a signal, sent to the process, called SIGSEGV, where the default behavior (if not handled by the process) is to abort. I'm not sure because I don't deal with Windows for a long time, but I believe an "Access Violation" aborts the Windows process as well (no signal sent!).

    There are other "fault" interrupts like "Page Fault" (trying to access a "page" of memory not present in physical memory), and there are "traps" (like "Breakpoint", ) and aborts (like "Double Fault" and "Machine Check" ) where there's no option unless to abort the source of the interrupt). See Intel SDM (Software Developemt Manuals) for more details.

    In short, segmentation fault aren't checked by YOUR code, but by the operation system. Your code can choose how to respond to this (in the example of SIGSEGV handler on Unix systems), but usually isn't a good idea since the fault leaves your program in an unstable state. In fact, signals hardware based as SIGSEGV, SIGBUS and SIGILL can abort the process whatever you do or never abort. See this:
    Code:
    #include <stdio.h>
    #include <unistd.h>
    #include <signal.h>
    
    static void segv_handler( int sig )
    {
      static const char msg[] = "Ouch!\n";
    
      // Using write() because it is Assynchronous Signal "safe" (routines from stdio aren't!).
      write( STDOUT_FILENO, msg, sizeof msg - 1 );
    }
    
    int main( void )
    {
      struct sigaction sa = { .sa_handler = segv_handler, .sa_flags = SA_INTERRUPT };
      char *p = NULL;
    
      sigaction( SIGSEGV, &sa, NULL );
    
      // this will generates a GPF, since 0 isn't a valid address on
      // process address space. GPF will be dealt by kernel and SIGSEGV
      // is sent to the process (the default handler is to print "Segmentation fault"
      // and abort).
      *p = 0;
    
      puts( "Ok!" );
    }
    In some systems "Ok" is never printed and "Ouch!" is printed once and the process aborted. In other systems "Ouch!" is printed ad infinitum. Maybe there are systems where "Ouch!" and "Ok!" are printed once and the program closes graciously (I've never seen one!). The usual end of SIGSEGV handler should be an exit() call, if you handle it. Add an exit( 1 ); at the end of segv_handler() and see "Ouch!" printed, instead of "segmentation fault".
    Last edited by flp1969; 01-17-2023 at 06:55 AM.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Possible Null dereference in code.
    By ghoul in forum C Programming
    Replies: 3
    Last Post: 05-07-2022, 06:49 AM
  2. pointer dereference
    By leo2008 in forum C Programming
    Replies: 2
    Last Post: 04-13-2021, 11:30 PM
  3. null pointer dereference
    By qwertylurker in forum C Programming
    Replies: 3
    Last Post: 03-14-2011, 12:06 AM
  4. Dereference a member of NULL ?
    By kbrandt in forum C Programming
    Replies: 4
    Last Post: 06-24-2009, 01:39 PM
  5. Dereference pointer to void pointer to member
    By phil in forum C Programming
    Replies: 5
    Last Post: 04-20-2005, 11:54 AM

Tags for this Thread