I'm working with an API that gives me a pointer for memory-mapped I/O. It does this by filling in a pointer-to-pointer argument:
int map(void** p);
Because this is memory mapped I/O, I'm pretty sure I should be using volatile here. (I don't know why they didn't make the parameter a volatile void**.)
But, my volatile void** isn't implicitly convertible to the function's void**, so I can't just pass it in directly:
volatile void* p;
map(&p); // Error: no known conversion from 'volatile void **' to 'void **'.
I'm currently working around this with an extra variable and a separate assignment step:
volatile void* p;
void* pNonVolatile;
map(&pNonVolatile);
p = pNonVolatile;
This seems verbose. Is it safe in this case to instead cast the volatile away when passing the pointer in? i.e.
volatile void* p;
map(const_cast<void**>(&p));
From a C++ language point of view, this could result in undefined behavior in the library, but not in your code using const_cast.
However, from what you have described, the library probably does not use C or C++ to write into this memory space (you mentioned it uses memory-mapped I/O). So the undefined behavior which could exist if the library dereferenced your pointer without volatile is not relevant, because hardware is doing that, not software.
In any case, whether you use const_cast or the "extra pointer then assign" solution doesn't seem to matter. They should be both OK if the memory is written by a hardware device, but not OK if it's written by the library without volatile.
Related
I have two pieces of code: The first, inside a C++ program, is where I load and call a function from an external test_lib.so:
typedef void *(*init_t)(); // init_t is ptr to fcn returning a void*
typedef void (*work_t)(void *); // work_t is ptr to fcn taking a void*
void *lib = dlopen("test_lib.so", RTLD_NOW);
init_t init_fcn = dlsym(lib, "test_fcn");
work_t work_fcn = dlsym(lib, "work_fcn");
void *data = init_fcn();
work_fcn(data);
The second piece of code is the one that compiles to test_lib.so:
struct Data {
// ...
};
extern "C" {
void *init_fcn() {
Data *data = new Data; // generate a new Data*...
return data; // ...and return it as void*
}
void work_fcn(void *data) { // take a void*...
static_cast<Data *>(data)->blabla(); // ...and treat it as Data*
static_cast<Data *>(data)->bleble();
}
}
Now, the first piece of code doesn't need to know what Data is, it just passes the pointer around, so it's a void*. But the library, which works directly with data's methods and members, needs to know, so it must convert the void*s to Data*s.
But the interface between the two pieces of code is just some functions with pointer arguments and/or return types. I could just keep the void* in the client, and change every instance of void* in the library to Data*. I did that, and everything works fine (my system is Linux/GCC 6.2.1).
My question is: was I lucky, or is this guaranteed to work everywhere? If I'm not mistaken, the result of calling some f(Data*) with a void* argument is just as if called reinterpret_cast<Data*> on the void* --- and that couldn't possibly be dangerous. Right?
EDIT: No, simply making the Data type transparent to the client code won't work. The client code calls many libraries through the same API, but each library might have its own implementation. For the client, Data could be anything.
Calling any function through the wrong function type is automatically undefined behavior. From C++ Standard draft n4604 (roughly C++17) [expr.reinterpret.cast]:
A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling a function through a pointer to a function type that is not the same as the type used in the definition of the function is undefined. Except that converting a prvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are function types) and back to its original type yields the original pointer value, the
result of such a pointer conversion is unspecified.
Calling any function through a function pointer type with the wrong linkage is also undefined behavior. Your typedefs don't use "C" linkage, ergo UB. From draft n4604 section [expr.call]:
Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function’s definition is undefined.
Besides that point, different pointer types are not required to have the same representation. (cv-qualified) void* can hold any object pointer, but its alignment restrictions are the same as char* (that is, no restriction) and as a result, it's not necessarily representation compatible with other object pointer types and may not even be the same size. (And most definitely, object pointers, function pointers, and the variations on pointer-to-member are frequently different sizes on real-world systems.)
While this is likely to work in practice, C doesn't guarantee this behavior.
There are two problems:
Different pointer types can have different sizes and representations. On such an implementation going to void * and back involves an actual conversion at runtime, not just a cast to make the compiler happy. See http://c-faq.com/null/machexamp.html for a list of examples, e.g. "The old HP 3000 series uses a different addressing scheme for byte addresses than for word addresses; like several of the machines above it therefore uses different representations for char * and void * pointers than for other pointers."
Different pointer types can use different calling conventions. For example, an implementation might pass void * on the stack but other pointers in registers. C doesn't define an ABI, so this is legal.
That said, you're using dlsym, which is a POSIX function. I don't know if POSIX imposes additional requirements that make this code portable (to all POSIX systems).
On the other hand, why don't you use Data * everywhere? On the client side you can just do
struct Data;
to leave the type opaque. This fulfills your original requirements (the client can't mess with the internals of Data because it doesn't know what it is, it can only pass pointers around), but also makes the interface a bit safer: You can't accidentally pass the wrong pointer type to it, which would be silently accepted by something taking void *.
You can make it cleaner by using opaque structure definitions. See the second half of the accepted answer here:
Why should we typedef a struct so often in C?
Thus the caller is handling pointers to a defined type, but cannot see inside what is being pointed at. The implementation has the actual struct definition, and can work with it. No more casting is required.
I'm using a library (ENet), which uses callbacks. In those callback functions, it passes a struct which contains a void* for user data, for your own use. I'd like to use that variable, but not as a pointer. I don't want to allocate memory just so I can point to it, I'd rather use the space of the void* directly to store a size_t.
But, as expected, when I cast the void* variable to a size_t variable, I get a strict alias warning. And the callback's struct doesn't provide a union to access it as something other than a void*.
I know I can disable that warning completely, but I'd rather just silence it for this particular case. Is there a way to write a cast of this sort that lets the compiler know it is intentional, to avoid the warning?
Edit:
Here is an example of what I'm trying to do. Since I need to be able to edit the user value, I'm casting it to size_t while also trying to grab a reference to it:
size_t& offset = reinterpret_cast<size_t&>(packet->userData);
This works, but gives the warning.
But, as expected, when I dereference the void* variable to a size_t variable, I get a strict alias warning.
If you want to use the void * itself just to transport a plain integer, you don't want to dereference it, you want to cast it to an appropriate integral type (intptr_t is your best bet, as the standard guarantees that it can survive to a roundtrip through void *).
intptr_t magic=42;
register_callback(&myfunc, (void *)magic);
// ...
void myfunc(void *context)
{
intptr_t magic=(intptr_t)context;
// ...
}
(if you like C++-style casts, those would all be reinterpret_cast)
Besides, you are probably doing something weird in your code, because void * (like char * and unsigned char *) is not subjected to the strict aliasing rule (they can alias any other pointer).
Update
Here is an example of what I'm trying to do. Since I need to be able to edit the user value, I'm casting it to size_t while also trying to grab a reference to it:
size_t& offset = reinterpret_cast<size_t&>(packet->userData);
This works, but gives the warning.
Nope, even assuming that size_t and void * had the same size and alignment requirements (which is not guaranteed), this cannot be done portably; aliasing a void *& with a size_t & is not allowed (also, this is particularly devious because it's hidden in a reference).
If you really need to do this, you have to come to terms with your compiler; in gcc, for example, you could compile just the file where you have this thing with -fno-strict-aliasing, which, instead of simply disabling the warning (=hiding the potential problem under the carpet), disables the compiler assumptions about strict aliasing, so that the generated code works correctly even if pointers/references to unrelated types point to the same stuff.
trying to understand the usage of const_cast. Code like the following:
const char* text="bb";
(const_cast<char&>(*text))='a';
cout<<*text;
...generates a runtime error.
Another question, in memory, how does the runtime (it) know that this area is const or not, what kind of flag is this ?
That code invokes undefined behaviour; it is not valid to write to a string literal (nor indeed to any const object).
The C++ standard does not define how this should fail (or even that it must fail). But on a typical platform, it will be up to the OS and the underlying hardware to detect the problem. The storage for "bb" will typically be in a dedicated section of the executable, which is marked as read-only. See e.g. http://en.wikipedia.org/wiki/Memory_protection.
However, there are uses of const_cast that don't invoke undefined behaviour. e.g.:
int x = 5; // Not a const object
const int *p = &x;
int *q = const_cast<int *>(p);
*q = 6; // This is ok
The string might be put in static memory. So it is an undefined behaviour.
Try this
char t[]="bb";
const char* text = t;
(const_cast<char&>(*text))='a';
cout<<*text;
You can only const_cast something which you know is not really const. In this case, even if text is const, we know that it points to t which is not const. Hence we can safely cast away the const.
Generally speaking, the run-time doesn't know whether a particular variable is actually const. If you cast away const-ness, you get undefined behavior if you end up writing to a variable defined as const (as opposed to a normal variable to which you happen to have a const pointer/reference).
If they wanted to mandate that the run-time "know" about things being const, then they'd probably prescribe specific behavior (e.g., throwing a particular exception) when/if you write to a const variable. Some systems would support that quite easily -- but others wouldn't, so a specific response isn't required.
I have fairly decent C++ skills, but this one cast has been giving me issues. I have a function that takes in the following parameters: (volatile void **, void * , void*). I have 3 int* variables and I am trying to pass them in as (&var1, var2, var3). However, I am getting the following error: Cannot convert parameter 1 from int** to volatile void**. Is there a specific cast that needs to be made to allow for this? Below is a snippet of code that I am using. Any help is greatly appreciated.
int* pVal = InterlockedCompareExchangePointer(&cur_val, new_val, old_val);
This is being done in VS2010 on a windows XP machine.
The first one should be volatile void ** and you have int **. You can either just cast to volatile void**, or (better) declare the original variable as volatile and then cast.
volatile means that the variable can be changed elsewhere outside of your code, and basically it means that the variable won't be optimized, but since your original variable is not defined as volatile it might still be optimized, and you would get incorrect results.
You can do a const_cast, but the best thing you can do is to declare your variable a volatile int* (i.e. pointer to volatile int) because otherwise the result might be undefined.
InterlockedCompareExchangePointer does an operation that may be beyond the optimizer's scope to analyze, so it's important that the variable is volatile to make sure its value is fetched from memory (and not cached in registers etc.) each time it is being used.
In addition to declaring the int as volatile, you still need to cast it as:
int* pVal = (int *)InterlockedCompareExchangePointer((void **)&cur_val, (void *)new_val, (void *)old_val);
Note the cast of the value returned from the function too. It returns a void *, so it must be cast to int *.
C++ requires explicit casts.
Most of the time, I am doing this way.
class a {
public:
~ a() {
i = 100; // OK
delete (int *)j; // Compiler happy. But, is it safe?
// The following code will lead compilation error : delete j;
}
private:
volatile int i;
volatile int *j;
};
int main() {
a aa;
}
However, I saw an article here:
https://www.securecoding.cert.org/confluence/display/seccode/EXP32-C.+Do+not+access+a+volatile+object+through+a+non-volatile+reference
Casting away volatile allows access to
an object through a non-volatile
reference. This can result in
undefined and perhaps unintended
program behavior.
So, what will be the workaround for my above code example?
Here is the error message I get if I use
delete j
Note that, this is output from VC6 (Don't ask why I am using VC6!)
c:\projects\a\a.cpp(5) : error C2664:
'delete' : cannot convert parameter 1
from 'volatile int *' to 'void *'
Conversion loses qualifiers
Nothing. If you don't access the volatile memory, the semantics of volatile are unaffected. If you accessed volatile memory through a casted non-volatile pointer, the compiler might optimize the reference away. If the value had changed, you'd have the wrong value. For some value of wrong. ;-)
The delete doesn't access the volatile memory, it just frees it. Sort of an uncommon thing to do with volatile memory.
deleteing a volatile would imply that you've serialized access to it so it is not, in fact, volatile any more. The proper way to remove the volatile (once you know it's safe) is with const_cast<int*>.
If the pointer, and not the int, is volatile, then you really meant int *volatile j. Moreover, if all the members of a class are volatile, you probably want to qualify the entire object at once, a volatile aa;.
It depends on the meaning you expect from your volatile variable. Right now, j is a pointer to a volatile integer; is that what you mean? If so, it's safe since you don't need to access the volatile value, just its address, which isn't volatile.
If, however, you meant that you want a volatile pointer to an integer, the required syntax is int* volatile j. In that case, it could be problematic to cast it to a non-volatile pointer first, but I don't think your compiler would complain if you tried to delete it as is. G++, for one, doesn't.
That should be fine, since you're not accessing the variable after casting away the volatile. However, I don't know why you'd get an error regardless. I tried that code myself, and everything seemed to go fine, what did you see happen?