Pointer safety and protection

Is there a generally accepted way to safely dereference a wild pointer to avoid a processor crash?

One possibility is to first check whether the pointer value lies within a safe memory space.

AVRs don't "crash"... :-)

westfw: AVRs don't "crash"... :-)

I can get my Zero, with a SAMD21 processor, to hang. One symptom is that the serial port no longer prints.

I think the trick is to always safely initialise the pointer to null, and never dereference it if it is null.

TolpuddleSartre: I think the trick is to always safely initialise the pointer to null, and never dereference it if it is null.

Yes, that was my first thought. So in the code:

Replace:
    var = *ptr;

With:
    If (ptr != NULL) {
        var = *ptr;
    }
    else {
        // exception handling code
    }

But that could quickly make the code ugly. Does anyone have an "elegant" example, maybe where they did something similar, or different?

But that doesn't handle the case where the pointer is, after initialization with NULL, inadvertently assigned a value outside of the valid memory space.

sthudium: But that could quickly make the code ugly. Does anyone have an "elegant" example, maybe where they did something similar, or different?

that kind of check is used quite frequently, mainly because pointers are rife with potential pitfalls like that.

common use example where you would definitely want to check to make sure that your function pointer isn't nullptr:

using functPtr = void(*)(void);

void setup() {
  Serial.begin(9600);
  runFunction(printSomething);
  delay(100);
  void* ptr = printSomething;
  runFunction(ptr);  // compiles (with a warning) and runs, the void pointer is implicitly cast to functPtr
  delay(100);
// you can try this too:
//  ptr = 0x00FF; // arbitrary address
//  runFunction(ptr);  //compiles but you'll get "undefined" behavior
//  delay(100);
  runFunction(nullptr); // compiles but you'll get "undefined" behavior
  delay(100);
  Serial.println(F("finished setup..."));
}

void loop() {

}

void printSomething() {
  Serial.println(F("Something"));
}

void runFunction(functPtr function) {
  function();
}

// this version handles the voidptr
//void runFunction(functPtr function) {
//  if(function) {
//    function();
//  } else {
//    Serial.println(F("Oopsie"));
//  }
//}

At the end of your day, the compiler is your friend. Make sure you have verbose reporting on to reduce your fears of some rogue pointer resulting in unexpected happenings

Conditional assignemt could be a one line sollution:

var = ptr ? *ptr : var;

Thanks, TolpuddleSartre, BulldogLowell, Danois90.

You guys present great ideas for handling NULL pointers.

However, I was thinking more about rogue pointers.

One solution could be a macro (possibly in Arduino.h) that does something like:

if (   (ptr < MEM_LOWER)            // MEM_LOWER is hardware dependent
    || (ptr > MEM_UPPER) ) {        // MEM_UPPER is hardware dependent

    // exception handling code
}

However, I was thinking more about rogue pointers.

Don't let the pointer go rogue is the only way I know, in the absence of an MMU. Simple bounds checking isn't necessarily going to help.

One possibility is to first check whether the pointer value lies within a safe memory space.

I was thinking more about rogue pointers.

Can you be a bit more explicit about the problems you’re trying to solve? Which chips? Pointers to static memory? Stack memory? Malloc’ed memory? What might make them rogue? Completely rogue, or just wrong?

Clearly all your code should have:

if (ptr_valid(p)) {
v = *p;
} else {
// magically fix everything!
}

Where ptr_valid() can vary from (1) to (p!=0) to arbitrarily complex…
An ATmega328 has 16bit pointers but only has a bit more than 2k of valid pointer values (including IO space, which you might not want to include.) On the one hand, that means if your pointer is getting “random damage”, then it’s “likely” that it won’t be within that 2k. On the other hand, it’s pushing plausibility to define “regions” within the 2k.
There are a couple of possibilities:
The memory space of the AVR is pretty well defined. Static and uninitialized variables in “low” memory, followed by malloced memory, and the stack growing from the top of memory downward. You could check for pointers pointing to space in between the top of malloced memory and the “bottom” of the stack - those should always be bogus. (easier if you don’t use malloc()) You could put a “guard word” or two at the beginning of structures:

   static inline boolean ptr_valid(p) {
     if (p < _datastart || p >heap_end)  // check value of ptr.
      return false;
    if (p->guard != p || p->magic != STRUCT_MAGIC)  // check guard word and magic number
      return false;
    return true;

I think the most common cause of “bad” pointers is not “rogue” pointers, but pointers to memory that ends up not containing the data any more. For example:

  char * format_output(int a, int b, int c) {
     char buffer[20];
     sprintf(buffer, "%d: %d/%d", a, b, c);
     return(buffer);
  }

“buffer” was a perfectly valid pointer. Briefly ! It’s not valid to return a pointer to a local variable…

Rouge pointer = bad programming :wink:

I would really like to see one example of good programming which leads to a rouge pointer. Returning a reference to a local buffer from a function does not apply to “good programming” :slight_smile:

westfw: Can you be a bit more explicit about the problems you're trying to solve?

I was trying to write a function that accepts a structure pointer, which I could reuse in other code. My concern was assisting debug when that function is improperly used and causes a crash. When debugging crashing code, the common debug technique is to comment out portions of code to isolate where the crash starts, and I thought there may be a easier (cleaner) way to debug if the function is prevented from crashing when it is improperly used (e.g. invoked before structures are defined).

From what I have read, it seems that the only safe method is for the function to check whether the pointer matches one of the structures in a list of applicable structures, and then flag an error if needed. But this consumes processor cycles, so that check should probably be enabled during debug.

sthudium: From what I have read, it seems that the only safe method is for the function to check whether the pointer matches one of the structures in a list of applicable structures, and then flag an error if needed. But this consumes processor cycles, so that check should probably be enabled during debug.

your compiler is good at telling you that your are passing the right kind of pointer.

There is no coercion of pointers in C++ but since arduino compiles with the -fpermissive flag it may allow some PODType coercion. So, you can see if pointers are coerced (as my example above) by looking at the compiler output (i.e. warnings).

It is useless to check to see if a pointer is within some range...

sthudium: ...I thought there may be a easier (cleaner) way to debug if the function is prevented from crashing when it is improperly used (e.g. invoked before structures are defined).

Again, the compiler is your friend, that's why it won't let you use a pointer to a struct that hasn't been defined!

You should provide a real-world example of whatever problem you are trying to solve...

BulldogLowell: Again, the compiler is your friend, that's why it won't let you use a pointer to a struct that hasn't been defined!

I'm thinking that an undefined pointer could occur with careless type casting.

To mee it sounds alot like you are trying to code your way out of a problem which is placed 20" in front of the screen :P ;)

As BulldogLowell, I would like to see an example where a "rouge pointer" could be an issue - the structure of an arduino program is IMO too simple for this to happen. I could to some degree understand the problem if it would happen in a multi-threaded environment where the pointer is referencing a shared resource, but this would again be a rookie mishap :)

I could to some degree understand the problem if it would happen in a multi-threaded environment where the pointer is referencing a shared resource, but this would again be a rookie mishap

...and would hopefully be trapped by the MMU

To mee it sounds alot like you are trying to code your way out of a problem which is placed 20" in front of the screen

I had to check. In my case, the problem is more like 24" in front of the screen.

One of the things I hate about C# is the insistence that pointers don't exist, when everything is a pointer, and the fact that you can't implicitly compare a pointer (object) to null. You must explicitly use "!= null".

There are, posted regularly on this forum, attempts to return pointers to memory that goes out of scope when a function ends, and plenty of attempts to pretend that pointers and arrays are complete interchangeable.

It is good that OP is at least aware that some checking of pointers IS useful, even if the examples, so far, are not all that good.

this check (along with array-access-out-of-bound check and others) would require run-time check. and C/C++ is all about no-run-time-check-whatsoever in the name of efficiency. but it makes sense especially on microprocessors because you would not want to waste memory for these “useless” check routines.

but you can look into <unique_ptr> for safe pointer references

Use references rather than pointers unless you need pointer arithmetic.

Danois90: To mee it sounds alot like you are trying to code your way out of a problem which is placed 20" in front of the screen :P ;)

I agree, it appears I am worrying about something that is extremely unlikely to happen.

But I did learn a lot, and I appreciate everyone who helped me.

Thanks, again.