Reading a struct from a read only memory - c++

I'm working on a embedded system, where some calibration data is stored in the flash memory. The calibration data is stored in a struct which is placed in a special section that the linker knows to place in the flash:
struct data_block {
calibration_data mData;
uint16_t mCheckSum;
};
//Define to compile the fixed flash location for image data
const data_block __attribute__((section (".caldata"))) gCalibrationData{};
where calibration_data is another POD struct which contains the actual values.
The problem is that if I now simply write the following:
const data_block data{gCalibrationData};
if (CheckSum(&(data.mData)) == data.mCheckSum) {
//do stuff
} else {
//Error
}
this always goes to the error branch, even though the actual checksum in flash is absolutely correct (writing this a bit differently makes it work, see below).
This is of course understandable: the compiler sees a const global object, which is default-initialized, so it knows all the values, so I guess it actually optimizes out the whole if (if I debug-printf data via a uint16_t *, I actually get the correct values).
The way I think would be correct is to define
const volatile data_block __attribute__((section (".caldata"))) gCalibrationData{};
However, now I have the problem that I can't assign a volatile struct to non-volatile, i.e. const data{gCalibrationData}; does not compile. The same problem also appears if I try to access through a const volatile data_block *.
There's at least two or three ways I can make this work, and I don't like any of them:
remove the const (and volatile) qualifier from gCalibrationData. However, this is a bit of a hack based on the compiler not being clever enough to guarantee that gCalibrationData is never touched in my program, and on the other hand, I'd like to keep to const qualifier, since trying to write to gCalibrationData by assigning is a hard fault.
access gCalibrationData via const gCalibrationData * volatile pData (yes, the volatile is exactly where I mean it). Accessing through a pointer which is volatile forces the compiler to actually load the data. Again, this seems like a hack, since the pointer itself certainly isn't volatile.
give data_block and calibration_data an assignment operator taking const volatile &, and assign field by field in them. This seems to be correct from the language point of view, but then whenever calibration_data changes I need to edit the assignment operator by hand. Failing to do so will produce hard-to-detect bugs.
My question: what would be the correct way to read the calibration data? My ideal criteria would be:
the global object itself is const, to catch unintended writes.
no undefined behaviour
access by assigning the struct directly to another struct
or at least so that I'm not required to remember to assign each variable of primitive type in calibration_data, see option 3. above
bonus points for thread-safety, although in my specific case only a single thread ever reads or writes the flash (all other "threads" are interrupts).

One solution could be to declare a buffer in a separate source file, to inform the linker of size of data_block and then define gCalibrationData to be a symbol whose value is the begining of this buffer:
data_block.cpp:
//no initialization performed here, just used to
//transmit to the linker the information of the size
//and alignment of data_block
extern "C"{//simpler name mangling
[[gnu::section(".caldata")]] volatile
aligned_storage<sizeof(data_block),alignof(data_block)> datablock_buffer;
}
//then we specify that gCalibrationData refers to this buffer
extern const volatile data_block
gCalibrationData [[gnu::alias("datablock_buffer")]];
Alternatively the definition of gCalibrationData symbol can be done via a linker script:
SECTIONS{
.caldata : {
gCalibrationData = . ;
data_block.o(.caldata)
}
}
gCalibrationData is an alias to an data_block_buffer. This will not cause undefined behavior because such aliasing is permitted by the language: data_block_buffer provides storage for gCalibrationData.
Semanticaly, the extern specifier is used to say that this declaration is not a definition of the value of gCalibrationData. Nevertheless the alias attribute is a definition of the symbol for the linker.
data_block.hpp
extern const volatile data_block gCalibrationData;
//and copy must be enabled for volatile:
struct data_block{
/*...*/
data_block(const data_block&) =default;
data_block& operator=(const data_block&) =default;
data_block(const volatile data_block& other){
//the const cast means: you are responsible not to
//perform this operation while performing a rom update.
memcpy(this,const_cast<const data_block*>(&other);
}
data_block& operator=(const volatile data_block& other){
memmove(this,const_cast<const data_block*>(&other);
//or memcpy if you are sure a self assignment will never happen.
return *this;
}
};

The most practical approach would be to lose the const. By a strict reading of the standard, gCalibrationData shouldn't be allowed to be const, since writing to a const object -- regardless of who does it -- leads to undefined behavior.
Failing that, though, just define it as extern const (and, if necessary to placate the linker, put the non-extern definition in its own translation unit. That will get you your const-correctness checking, allow the compiler to, e.g., do hoisting optimizations based on the initial values of the calibration data, while still preventing it from making any specific assumptions about those values at compile time.

Related

Should I qualify pointer parameters with volatile if they may be changed during the execution of a function?

Say I have the function
int foo(int * const bar){
while(!*bar){
printf("qwertyuiop\n");
}
}
where I intend to change the value at bar to something other than 0 to stop this loop. Would it be appropriate to instead write it as below?
int foo(int volatile * const bar){
while(!*bar){
printf("qwertyuiop\n");
}
}
volatile was intended for things like memory-mapped device registers, where the pointed-to value could "magically" change "behind the compiler's back" due to the nature of the hardware involved. Assuming you're not writing code that deals with special hardware that might "spontaneously" change the value that bar points to, then you needn't (and shouldn't) use the volatile keyword. Simply omitting the const keyword is sufficient to let the compiler (and any programmer that might call the function) know that the pointed-to value is subject to change.
Note that if you are intending to set *bar from another thread, then the volatile keyword isn't good enough; even if you tag the pointer volatile, the compiler still won't guarantee correct handling. For that use-case to work correctly, you need to either synchronize all reads and writes to *bar with a mutex, or alternatively use a std::atomic<int> instead of a plain int.

Why does not my compiler show an error when I want to modify a pointer to a constant integer?

This is the code.
int main()
{int v=2;
const int *p=&v;
++v; //Option 1: Does work, but why should it?
// ++*p; //Option 2: Does not work
}
The compiler throws an error for option 2, as expected. But it goes with option 1, when it is modifying the content of a pointer to a constant integer. Why? Or, am I understanding something wrong about the implication of const? Is it applicable only for variables on the heap as opposed to the stack?
Or, am I understanding something wrong about the implication of const?
Yes.
When you have:
int v = 2;
const int *p=&v;
You are not allowed to modify the object through p but you are still allowed to modify the object directly through v. You may also modify the object through another pointer.
int* p2 = &v
*p2 = 10; // OK.
const doesn't really mean 'constant', it basically means "read only". When you define a pointer to a const object, it doesn't mean that object can never change--it just means that you can't write to that object via that pointer.
In fact, it's perfectly allowable (and sometimes meaningful) to specify that an object is both const (so you can't change it) and volatile (indicating that something else might change it). For example, back in the MS-DOS days, the BIOS maintained a timer at a an address of 40:6c (offset 0x6c in segment 0x40), which was updated every ~55 ms, but you shouldn't write it directly, so you could define a pointer to it like:
long const volatile *bios_timer = MK_FP(0x40, 0x6c);
So, attempting to write to this location (at least via this pointer) was not allowed, but the value you'd read from it would change on a regular and ongoing basis.
[Note that contrary to how it may sound above: this (presumably) still exists--but with a protected mode OS, attempting to access it directly in user mode will undoubtedly fail.]

Putting a const in a header

From everything I am reading and testing, there is no way (without a preprocessor macro) to define a constant in a shared header and ensure that each TU is not creating its own storage for that constant.
I can do this:
const int maxtt=888888;
Which is the same exactly as:
static const int maxtt=888888;
And if this header is shared, it will work but each TU gets its own copy of maxtt. I could also do this, to prevent that:
extern const int maxtt;
But then I cannot define maxtt here; that must be done in a CPP to avoid linker error.
Is my understanding correct?
Since the variable is constant, the fact that each TU gets its own copy is usually irrelevant.
In C++, constants at namespace scope are implicitly static for this reason. Often this allows for better code than if you only had a single instance with external linkage, since (if the variable is actually a constant expression) the constant can often be folded right into the usage site and doesn't need to be stored at all.
So unless you really need to take the address of the constant, or something like that, you should stick with the static version. (And as you already observed, you can force external linkage by adding extern.) Another reason may be that you're initializing dynamically and only want one call to the initializer:
// header:
extern int const n;
// one implementation:
int const n = init_function_with_side_effects();
The static construction (int const n = init(); in the header) would cause the function to be called once in every TU.
You write,
“From everything I am reading and testing, there is no way (without a preprocessor macro) to define a constant in a shared header and ensure that each TU is not creating its own storage for that constant.”
Happily that’s incorrect.
For a small integral value you can always just use an enum. The trade-off is that you can’t pass the address of an enum value, because it has no address. It’s pure value.
However, saving space for an integral value is a pretty meaningless thing to do, since it’s so small.
So, let’s consider a biggie thingy,
struct BiggyThingy
{
unsigned char zeroes[1000000];
BiggyThingy(): zeroes() {}
};
Now how can we declare a BiggyThingy constant in a header file and ensure a single one overall for the whole program?
Using an inline function.
Well the simplest is this:
inline BiggyThingy const& getBiggyThingy()
{
static BiggyThingy const theThingy;
return theThingy;
}
static BiggyThingy const& biggyThingy = getBiggyThingy();
If you don’t want a reference taking up space (like a pointer) in each translation unit, then just use the function without the notation-simplifying reference.
Using the template constant trick.
Here is another way to provide the constant, leveraging a special rule for templates instead:
template< class Dummy >
class BiggyThingyConstant_
{
public:
static BiggyThingy const value;
};
template< class Dummy >
BiggyThingy const BiggyThingyConstant_<Dummy>::value;
typedef BiggyThingyConstant_<void> BiggyThingyConstant;
which can be accessed like
foo( BiggyThingyConstant::value )
Or if you want nicer notation you can add a reference per translation unit, as for the inline function solution.
Disclaimer:
Code untouched by compiler.
But you get the ideas, I think. ;-)
This code generates a constant in the TU only if you apply any operation that requires the address of the constant.
static int maxtt = 888888;
int * pmaxtt = &maxtt; //address of constant requested.
This may work as well and avoids the linker problem (though it'll store maxtt in each TU if the address is requested):
constexpr int maxtt = 888888;
Avoid the extern construction as it can't be optimized.
If you're so worried about storage, use an enumeration:
enum { maxtt = 888888 };
Enumerators are scalar rvalues and hence do not require storage. It is illegal to say &maxtt.
Indeed, your understanding of the semantics are correct.
In practice, each translation unit might not get a copy of the storage for the integer. One reason is that the compiler might implement the value as a literal wherever it is referenced. The linker might also be smart enough to discard the storage if it finds it isn't referenced.
The compiler might not be free to use a literal for your constant. You might take a reference to that integer, or get a pointer to it. In that case, you need the storage -- and you might even need the cross-compiland uniqueness. If you take the address of your const symbol in each compilation unit, you might find that its different since each object will get a unique, static copy.
You might have a similar problem if you use an enum; your const int has storage, and you can take the address of that storage. You can't take the address of an enumerand until you store it someplace.

const cast to a global var and program crashed (C++)

int main()
{
const int maxint=100;//The program will crash if this line is put outside the main
int &msg=const_cast<int&>(maxint);
msg=200;
cout<<"max:"<<msg<<endl;
return 0;
}
The function will run ok if the 'const int maxint=100;' definition is put inside the main function but crash and popup a error message said "Access Violation" if put outside.
Someone says it's some kind of 'undefined behavior', and i want to know the exact answer and how i can use the const cast safely?
They are correct, it is undefined behaviour. You're not allowed to modify the value of a const variable, which is the danger of casting away the constness of something: you better know it's not really const.
The compiler, seeing that maxint is const and should never be modified, doesn't even have to give it an address. It can just replace all the uses of maxint with 100 if it sees fit. Also it might just put the constant in to a portion of memory that is read-only, as Matteo Italia points out, which is probably what's happening for you. That's why modifying it produces undefined behaviour.
The only way you can safely cast away the constness of a variable is if the variable is not actually const, but the const qualifier was added to a non-const variable, like this:
int f(const int& x) {
int& nonconst = const_cast<int&>(x);
++nonconst;
}
int blah = 523;
f(blah); // this is safe
const int constblah = 123;
f(constblah); // this is undefined behaviour
Think about this example, which compiles perfectly:
int f(const int& x) {
int& nonconst = const_cast<int&>(x);
++nonconst;
}
int main() {
f(4); // incrementing a number literal???
}
You can see how using const_cast is pretty dangerous because there's no way to actually tell whether a variable is originally const or not. You should avoid using const_cast when possible (with functions, by just not accepting const parameters).
Modifying an object that is const (with the exception of mutable members) results in undefined behavior (from the C++03 standard):
7.1.5.1/4 "The cv-qualifiers"
Except that any class member declared mutable (7.1.1) can be modified,
any attempt to modify a const object during its lifetime (3.8) results
in undefined behavior.
The above undefined behavior is specifically called out in the standard's section on const_cast:
5.2.11/7 "Const cast"
[Note: Depending on the type of the object, a write operation through
the pointer, lvalue or pointer to data member resulting from a
const_cast that casts away a const-qualifier68) may produce undefined
behavior (7.1.5.1). ]
So, if you have a const pointer or reference to an object that isn't actually const, you're allowed to write to that object (by casting away the constness), but not if the object really is const.
The compiler is permitted to place const objects in read-only storage, for example. It doesn't have to though, and apparently doesn't for your test code that doesn't crash.
You are only allowed to cast away constness of an object which is known not to be const. For example, an interface may pass objects through using a const pointer or a const reference but you passed in an object which isn't const and want/need to modify it. In this case it may be right thing to cast away constness.
On the other hand, casting away constness of an object which was const all the way can land you in deep trouble: when accessing this object, in particular when writing to it, the system may cause all kinds of strange things: the behavior is not defined (by the C++ standard) and on a particular system it may cause e.g. an access violation (because the address of the object is arranged to be in a read-only area).
Note that despite another response I saw const objects need to get an address assigned if the address is ever taken and used in some way. In your code the const_cast<int&>(maxint) expression essentially obtains the address of your constant int which is apparently stored in a memory area which is marked to be read-only. The interesting aspect of your code snippet is that it is like to apparently work, especially when turning on optimization: the code is simple enough that the compiler can tell that the changed location isn't really used and doesn't actually attempt to change the memory location! In this case, no access violation is reported. This is what apparently is the case when the constant is declared inside the function (although the constant may also be located on the stack which typically can't be marked as read-only). Another potential outcome of your code is (independent of whether the constant is declared inside the function or not) is that is actually changed and sometimes read as 100 and in other contexts (which in some way or another involve the address) as 200.

when should a member function be both const and volatile together?

I was reading about volatile member function and came across an affirmation that member function can be both const and volatile together. I didn't get the real use of such a thing. Can anyone please share their experience on practical usage of having member function as const and volatile together.
I wrote small class to test the same:
class Temp
{
public:
Temp(int x) : X(x)
{
}
int getX() const volatile
{
return X;
}
int getBiggerX()
{
return X + 10;
}
private:
int X;
};
void test( const volatile Temp& aTemp)
{
int x = aTemp.getX();
}
int main(int argc, char* argv[])
{
const volatile Temp aTemp(10);
test(aTemp);
return 0;
}
The cv qualification distilled means:
I won't change the value, but there is something out there that can.
You are making a promise to yourself that you won't change the value (const qualification) and requesting the compiler to keep its slimy hands off of this object and turn off all optimization (volatile qualification). Unfortunately, there is little standard among the compiler vendors when it comes to treating volatile fairly. And volatile is a hint to the compiler after all.
A practical use case of this is a system clock. Supposing 0xDEADBEEF was your system specific address of a hardware clock register you'd write:
int const volatile *c = reinterpret_cast<int *>(0xDEADBEEF);
You can't modify that register value, but each time you read it, it is likely to have a different value.
Also, can use this to model UARTs.
You asked for a practical example of volatile member functions. Well i can't think of one because the only situations i could imagine are so low-level that i would not consider using a member function in the first place, but just a plain struct with data-members accessed by a volatile reference.
However, let's put a const volatile function into it just for the sake of answering the question. Assume you have a port with address 0x378h that contains 2 integers, 4 bytes each. Then you could write
struct ints {
int first;
int second;
int getfirst() const volatile {
return first;
}
int getsecond() const volatile {
return second;
}
// note that you could also overload on volatile-ness, just like
// with const-ness
};
// could also be mapped by the linker.
ints const volatile &p = *reinterpret_cast<ints*>(0x378L);
You are stating
I'm not changing them, but another thing outside this abstract semantics could change it. So always do a real load from its address.
Actually, volatile signals that the value of an object might not be the value last stored into it but is actually unknown and might have been changed in between by external (not observable by the compiler) conditions. So when you read from a volatile object, the compiler has to emulate the exact abstract semantics, and perform no optimizations:
a = 4;
a *= 2;
// can't be optimized to a = 8; if a is volatile because the abstract
// semantics described by the language contain two assignments and one load.
The following already determines what volatile does. Everything can be found in 1.9 of the Standard. The parameters it talks about are implementation defined things, like the sizeof of some type.
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below. [...]
A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible execution sequences of the corresponding instance of the abstract machine with the same program and the same input. [...]
The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.
I've never needed anything being both const and volatile, but here's my guess:
Const: You, your code, is not allowed to change the value.
Volatile: The value may change over time without your program doing anything.
So some read-only data exposed by another process or by some hardware would be const and volatile. It could even be memory-mapped into your process and the page marked read-only, so you'd get an access violation if you tried to write to it if it wasn't const.
I think that the reason we have "const volatile" functions is the same as the reason we have "protected" inheritance: The grammar allows it , so we had better think up a meaning for it.
One situation I can think of that could require both const and volatile on a member function would be in an embedded systems situation where you had a the function was logically const but actually had to modify a data cache in a shared memory location (e.g. building a bitmap on demand and caching the bitmap in case the same bitmap was needed again soon). It certainly does not come up very often.
An object marked as const volatile will not be allowed to change by the code where it is declared. The error will be raised due to the const qualifier. The volatile part of the qualifier means that the compiler cannot optimize the code with respect to the object.
In an embedded system this is typically used to access hardware registers that can be read and are updated by the hardware, so it makes no sense to be able to write to the register via the code. An example might be the status register of a serial port.Various bits will indicate a status like if a character is waiting to be read. Each read to this status register could result in a different value depending on what else has occurred in the serial port hardware. It makes no sense to write to the status register but you need to make sure that each read of the register results in an actual read of the hardware.
Below is an illustration :
//We assume that the below declared pointers
//point to the correct
//hardware addresses
unsigned int const volatile *status_reg;
unsigned char const volatile *recv_reg;
#define CHAR_READ 0x01
int get_next_char()
{
while((*status_reg & CHAR_READ) == 0);
return *recv_reg;
}
Hope this helps.
Regards
Sandipan Karmakar.