home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c      Meh, in C you gotta define EVERYTHING      243,242 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 242,821 of 243,242   
   Waldek Hebisch to David Brown   
   Re: NULL dereference in embedded [was: O   
   06 Jan 26 13:08:57   
   
   From: antispam@fricas.org   
      
   David Brown  wrote:   
   > On 04/01/2026 00:25, highcrew wrote:   
   >> On 1/4/26 12:15 AM, highcrew wrote:   
   >>> I have a horrible question now, but that's for a   
   >>> separate question...   
   >>   
   >> And the question is:   
   >>   
   >> Embedded systems.  Address 0x00000000 is mapped to the flash.   
   >> I want to assign a pointer to 0x00000000 and dereference it to   
   >> read the first word.   
   >> That's UB.   
   >>   
   >> How do I?   
   >>   
   >> Now I guess that an embedded compiler targeting that certain   
   >> architecture where dereferencing 0 makes sense will not treat   
   >> it as UB.  But it is for sure a weird corner case.   
   >>   
   >   
   > There are some common misconceptions about null pointers in C.  A "null   
   > pointer" is the result of converting a "null pointer constant", or   
   > another "null pointer", to a pointer type.  A null pointer constant is   
   > either an integer constant expression with the value 0 (such as the   
   > constant 0, or "1 - 1"), or "nullptr" in C23.  You can use "NULL" from   
   >  as a null pointer constant.   
   >   
   > So if you write "int * p = 0;", then "p" holds a null pointer.  If you   
   > write "int * p = (int *) sizeof(*p); p--;" then "p" does not hold a null   
   > pointer, even though it will hold the value "0".   
   >   
   > On virtually all real-world systems, including all embedded systems I   
   > have ever known (and that's quite a few), null pointers correspond to   
   > the address 0.  But that does not mean that dereferencing a pointer   
   > whose value is 0 is necessarily UB.   
   >   
   > And even when dereferencing a pointer /is/ UB, a compiler can handle it   
   > as defined if it wants.   
   >   
   > I think that if you have a microcontroller with code at address 0, and a   
   > pointer of some object type (say, "const uint8_t * p" or "const uint32_t   
   > * p") holding the address 0, then using that to read the flash at that   
   > address is UB.  But it is not UB because "p" holds a null pointer - it   
   > may or may not be a null pointer.  It is UB because "p" does not point   
   > to an object.   
   >   
   > In practice, I have never seen an embedded compiler fail to do the   
   > expected thing when reading flash from address 0.  (Typical use-cases   
   > are for doing CRC checks or signature checks on code, or for reading the   
   > initial stack pointer value or reset vector of the code.)  If you want   
   > to be more confident, use a pointer to volatile type.   
      
   For curiosity I tried the following:   
      
   #include    
      
   uint32_t   
   read_at0(uint32_t * p) {   
       if (!p) {   
           return *p;   
       } else {   
           return 0;   
       }   
   }   
      
   that is we read trough a pointer only when it is a null pointer.   
   Using gcc-12 with command line:   
      
   arm-none-eabi-gcc -O3 -fverbose-asm -fno-builtin -Wall -g  -mthumb   
   -mcpu=cortex-m3 -c ts_null.c   
      
   I get the following assembly:   
      
   00000000 :   
      0:   b108            cbz     r0, 6    
      2:   2000            movs    r0, #0   
      4:   4770            bx      lr   
      6:   6803            ldr     r3, [r0, #0]   
      8:   deff            udf     #255    @ 0xff   
      a:   bf00            nop   
      
   So compiler generates actiual access, but then, instead of returning   
   the value it executes undefined opcode.  Without test for null   
   pointer I get simple access to memory.   
      
   So at least with gcc access works as long as compiler does not   
   know that it is accessing null pointer.  But if compiler can   
   infer that pointer is null generated code may do strange   
   things.   
      
   Putting volatile qualifier on p gives working code, but apparently   
   disables optimization.  Also, this looks fragile.  So if I needed   
   to access address 0 I probably would use assembly routine to do this.   
      
   --   
                                 Waldek Hebisch   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca