0

I've written a program which writes one float value to one place past the end of an array. I have the code and the compiled binary file. Am I able to somehow determine if I'm lucky and the program will work forever?

The program we're talking about is for ESP8266.

Defozo
  • 2,946
  • 6
  • 32
  • 51
  • 1
    No. The C++ standard makes no such guarantee to you, whatsoever. – Sam Varshavchik Jul 14 '17 at 11:10
  • Am I able to at least determine what will be corrupted then? – Defozo Jul 14 '17 at 11:11
  • 2
    If you set up a sufficiently accurate simulator, or some kind of a virtual machine, and use debugging tools to precisely evaluate the state of the program's state at the time that undefined behavior occurs; and do sufficient research to analyze and isolate any target platform-specific variables that may affect the runtime environment, and what would be their impact on undefined behavior, then there's you might be able to reach some kind of a conclusion. Or you can simply fix the bug. Pick what's easier. – Sam Varshavchik Jul 14 '17 at 11:14
  • 1
    Lok at your linker maps and use your debugger to find out what it being written where. Note well that such an analysis is a guide only, and the sword of UB will be forever hanging over your head;( – Martin James Jul 14 '17 at 11:14
  • 1
    Yeah - what @SamVarshavchik says. Fix it and provide the customers with a 'Free Performance Upgrade!' – Martin James Jul 14 '17 at 11:15
  • 1
    Or a "Security Update" which is quite possibly technically accurate depending on the scenario. But to answer the question, you could put some effort into it and determine if it's "be OK" or not. Start with, is the array on the stack or on the heap? If stack, you might be able to determine what's impacted. Is there any allocation alignment happening that might "allow" for a pseudo-safe use of a little more data than you requested? Etc. – mark Jul 14 '17 at 11:54
  • 1
    Why do you want to do this? – KjMag Jul 14 '17 at 11:59
  • In this case I'm able to update the firmware. However, I wanted to know what to do if both operations - updating or risking failure would cost money. – Defozo Jul 14 '17 at 12:11
  • You could soak-test the program for all hardware, environments, and scenarios that you expect to be fully representative of all clients... but I don't know how much it would really tell you; absence of the problem manifesting doesn't mean it never will, as it might depend on some corner case that you didn't check or it might only occur sporadically a tiny proportion of the time. – underscore_d Jul 14 '17 at 13:19

1 Answers1

1

In order to find out what happens in your case you have to find out what precisely are the memory locations you could erroneously access.

There are two things I would expect could happen: you overwrite data you should not, or you write to a memory location that is somehow protected and generate an unexpected interrupt (I am not sure if the ESP32 supports memory protection and whether you use it).

I hope your binary has debug information, otherwise this is going to be much more work. If you have a reasonably high quality debugger you should be able to proceed. Objectdump (assuming you use the GNU toolchain) will also help.

First you need a list of all arrays that are potentially accessed by the function. This is easy if it is a local or static variable directly referenced in the function. If the array is passed to your function in a pointer, you need to trace this back to find all arrays that could be passed to your function. For each array that your function may access, you have to do the following analysis:

Where is the array allocated? Is it a static variable, a stack variable or allocated on the heap?

Statically allocated arrays

The address of the array is constant in this case and you can find out its address by consulting the symbol table of your binary.

You could use objdump --syms and look where the array is (or use the debugger). Then you try to find which symbol comes next. This is the variable that will be overwritten. If you do not find a variable at the next address, check whether the address may be past the end of internal memory on the chip or enter into another section (possibly the stack).

Stack arrays

For these you will have to find out what is allocated where on the stack. List the local variables in a debugger and look at the addresses, if one is right behind your array, you know what gets overwritten. Otherwise read up on the calling convention used by your compiler and/or look at the assembly to find out what happens to the overwritten data. It could be that some unnamed temporaries are located at the location of the erroneoous write.

AFAIK the stack on the ESP32 grows down, so if the array is the last variable in the stack frame, you will overwrite the first variable in the allocating function's caller's stack frame (unless there is some space reserved due to alignment). You can probably check that in the debugger. From what I read in the Xtensa manual, the stack pointer and return address should be passed in registers.

Heap arrays

For these you will have to understand the malloc implementation you are using. If you are lucky the array's size is rounded up to some alignment. Otherwise you may overwrite either other heap data or some memory used by malloc to manage the heap. Either would certainly warrant a bug-fix, as you can hardly predict what will happen.

Arrays inside a struct or other Array

Regardless where these are allocated, there may be other members of a struct past the array, so you can predict what will happen when these are overwritten. There may also be padding due to alignment (check sizeof(YourStruct)). If the array is part of an array of arrays and not the last, you will likely overwrite the first entry of the following array.

I am not sure if this covers your situation, but I hope it gives you a starting point for analyzing the problem. Regardless, you may reach a point where further analysis will cost you more than a bugfix release.

PaulR
  • 3,587
  • 14
  • 24