Here are some sample classes to reproduce the situation I'm facing:
class A {
B* seccond;
}
class B {
int * number;
}
static NTSTATUS Read(std::uintptr_t address, size_t size, PVOID buff);
// Let's assume we have object 'obj' which has valid address of number variable
int buff;
Read(obj.seccond, sizeof(int), &buff);
Error: cannot convert argument 1 from 'int *' to 'uintptr_t'
I know it can be fixed easily with:
Read(std::uintptr_t(obj.seccond), sizeof(int), &buff);
but this is not satisfying enough, since it lowers code readability and it's just ugly. I really don't want to use templates since they're already everywhere all over my code.
Is there any simple container for such variables? Or some more elegant way of doing it?
EDIT: I've re-adapted question, sorry
You might use overload to do the conversion at one place
static NTSTATUS Read(const void* p, size_t size, PVOID buff)
{
return Read(std::uintptr_t(p), size, buff);
}
You are using one int* since your function wait for uintptr_t.
One is signed, the other is unsigned.
Try to use unsigned instead of int or try to use std::intptr_t instead of std::uintptr_t
EDIT :
A way to solve your problem could be something like that :
class B {
int *number;
operator int*() {
return number;
}
};
After, you can do something like :
Read(*objA.second, ...);
The answer from Jarod42 can be good as well !
I suppose you could use a void pointer as an argument.For example:
static NTSTATUS Read(void* address, size_t size, PVOID buff);
But you should probably pass an other argument to the function in order to determine the type that you should cast the address variable to.So for example:
static NTSTATUS Read(void* address,unsigned code, size_t size, PVOID buff)
{
//code could be int=1,float=2,...
switch(code)
{
//handle each case int,float,custom type ...
//by casting the address to the corresponding type(code)
}
}
Related
Lets have following function:
int encode(uint8b *dest, MyType srcType, const void *src)
{
uint32b value = 0;
uint64b value64 = 0;
switch (srcType)
{
case MyType_Usint: value = (uint32b)*(uint8b*)src; break;
case MyType_Uint: value = (uint32b)*(uint16b*)src; break;
case MyType_Udint: value = *(uint32b*)src; break;
case MyType_Ulint: value64 = *(uint64b*)src; break;
}
// now encode value to dest
}
I have passed wrongly aligned uint8b Data[sizeof(uint64b)]as src, I will fix the alignment.
But I received a demand to cast Data when calling the function to proper type, i.e. encode(dest, MyType_Uint, (uint16b*)Data), which I think would cause in some more annoying unnecessary switches.
It's working even with the wrong alignment on platforms accessible for me, but I'm not sure, how it affects the other.
Would such cast fix alignment and/or endianess?
And yes, I really need the void* parameter.
encode(dest, MyType_Uint, (uint16b*)Data)
Would such cast fix alignment and/or endianess?
Such cast does not fix alignment nor endiannes.
The way to call that function without undefined behaviour is following:
uint16b u = some_value;
encode(dest, MyType_Uint, &u);
uint64b ul = some_other_value;
encode(dest, MyType_Ulint, &ul);
Does such cast actually do anything?
Such cast changes the type of the expression. In this case, the C style explicit conversion does reinterpret cast.
The converted pointer can be used only in limited ways. You can convert it back to the original type (uint8b* in your case). Indirection through the pointer is UB in most cases, with few exceptions, which include pointer-interconvertible objects, as well as using a pointer to a narrow character type as the result of the conversion. There is no exception that would apply to your example, so it would have UB.
Note that for some pointers, the C style explicit conversion does static cast, rather than reinterpret cast. For example, when the pointers are to classes in the same inheritance hierarchy. This is why C style casts are to be avoided: Use the cast that you intend to use.
Casting a pointer never fix alignment nor endianness. It just re-interpret the address as pointing to a different type, and standard does not allow to de-reference it unless an object of the appropriate type lies at that address.
The conformant way to use a possibly misaligned representation is to use memcpy:
int encode(uint8b *dest, MyType srcType, const void *src)
{
uint32b value = 0;
uint64b value64 = 0;
switch (srcType)
{
// any object can be accessed through a char pointer
case MyType_Usint: uint8b tmp8 = *(uint8b*)src; value = tmp8; break;
// use a temporary for 16 bits type (endianness question)
case MyType_Uint: uint16b tmp16; memcpy(&tmp16, src, sizeof(tmp16));
value = tmp16; break;
// directly memcpy into the value when size is the same
case MyType_Udint: memcpy(&value, src, sizeof(value)); break;
case MyType_Ulint: memcpy(&value64, src, sizeof(value64)); break;
}
// now encode value to dest
}
Intel type (80x86 to core) are known to be tolerant to misalignment, but other processors are not and raise an error if you attempt a misaligned access.
This code is unlikely to work on platform that can't do unaligned memory access (like ARM9/ARM64 etc...).
This is because when you do value64 = *(uint64b*)src you expect the CPU to access a 8 bytes word (and as such it must be aligned to 64bit address) and the signature of the function does not guaranty this.
Typically, on such platform, calling:
char s;
int a = encode(dest, MyType_Ulint, &s);
will compile, and will crash at runtime (but will run ok on x86/amd64 system, yet with undefined behavior).
If you want something portable, you should do something like this:
enum MyType
{
MyType_Usint,
MyType_Uint,
MyType_Udint,
MyType_Ulint
};
int encode(uint8b *dest, MyType srcType, const void *src)
{
uint32b value = 0;
uint64b value64 = 0; // This is guaranted to be aligned for 64bit access
size_t expected_operand_size[] = { 1, 2, 4, 8 };
memcpy(&value64, src, expected_operand_size[(int)srcType]);
switch (srcType)
{
case MyType_Usint: value = *(uint8b*)&value64; break;
case MyType_Uint: value = *(uint16b*)&value64; break;
case MyType_Udint: value = *(uint32b*)&value64; break;
case MyType_Ulint: break;
}
// now encode value to dest
}
By the way, you should use template code here for convenience and to avoid the (useless) copy and be easier to understand (no need to have an type enum) :
template <typename T>
struct Encode
{
static uint64b convert(const void * src) { T t; memcpy(&t, src, sizeof(t)); return t; }
static uint64b convert(const T * src) { return *src; }
};
// Specialisation when we can avoid the copy
template <>
struct Encode<uint8b>
{
static uint64b convert(const void * src) { return (uint8b)*src; }
static uint64b convert(const uint8b * src) { return *src; }
};
template <typename T>
int encode(uint8b * dest, const void* src)
{
uint64b value64 = Encode<T>::convert(src);
// your encoding code here
}
// Use like this:
void * s = ...;
uint16b * s2 = ...;
uint32b * s3 = ...;
encode<uint8b>(dest, s); // No copy, calls Encode<uint32b>::do(const void*)
encode<uint16b>(dest, s2); // No copy, calls Encode<uint16b>::do(const uint16b*)
encode<uint32b>(dest, s3); // No copy, calls Encode<uint32b>::do(const uint32b*)
// or this is also safe
encode<uint16b>(dest, s); // Copy here for fixing alignment
I'm trying to make a function that takes a void*, copies some memory to it, and then moves the pointer.
Since it is a void pointer, I thought I'd cast it to char* and move that, like so:
PVOID SendAndMoveHead(PVOID dest, const Message& message, const size_t& size)
{
PVOID ret = CopyMemory(dest, (PVOID)message.msg.c_str(), size);
((char*)dest) += size;
return ret;
}
However, VS complains about ((char*)dest) saying
expression must me a modifiable lvalue
which I thought it was, since the following works:
PVOID SendAndMoveHead(PVOID dest, const Message& message, const size_t& size)
{
PVOID ret = CopyMemory(dest, (PVOID)message.msg.c_str(), size);
char* d = (char*)dest;
d += size;
return (PVOID)d;
}
If someone could shed some light on why the first version shouldnt work I'd really appreciate it.
((char*)dest) gives you a new temporary char *. ((char*)dest) += size; would change the temporary and have no effect, which causes a compilation failure.
In the second example d is not a temporary and lives long enough to get returned.
Alternatively you could write return (char*)dest + size;.
I want to do this conversion using C++ format, it works on the C way. but it fails when I try on C++ format.
It works!
void req_password(const void *data, size_t datalen)
{
char *password_old = ((char **) data)[0];
char *password_new = ((char **) data)[1];
...
}
It fails
void req_password(const void *data, size_t datalen)
{
char *password_old = (const_cast<char **>(data))[0];
char *password_old = (const_cast<char **>(data))[1];
...
}
error:
error: invalid const_cast from type 'const void*' to type 'char**'
So my doubt is, how could I do this conversion using the C++ way?
PS: This code is part from a API, I can't control the the input of data.
Don't.
If you are being given immutable data, then you are being given immutable data and that is the end of it!
First, here's what I suggest for maximum safety. Coercing data into its real type is a little tricky, alas:
void req_password(const void* data, size_t datalen)
{
const char* password_old = (reinterpret_cast<const char* const*>(data)[0]);
const char* password_new = (reinterpret_cast<const char* const*>(data)[1]);
// ...
}
(I've actually added some constness in the above, as it seems to be the intent of having const void* in the first place.)
But, if you really want the strings to be mutable, then this is fine too:
void req_password(const void* data, size_t datalen)
{
char* password_old = (reinterpret_cast<char* const*>(data)[0]);
char* password_new = (reinterpret_cast<char* const*>(data)[1]);
// ...
// More obvious when you recall that `const void*` is actually `void const*`;
// So:
// void const*
// becomes:
// char* const*
}
Notice how you don't even need const_cast here, because you're not modifying the thing that data points to: you are dereferencing it and getting its pointee.
Of course, ideally, data would point to a const std::string instance.
I have two functions with a little different functionality, so I can't make them as template functions.
int func64(__int64 a) {
return (int) a/2;
}
int func32(int a) {
return a--;
}
Depending on variable b64, I would like to call func64 or func32. I don't want check if b64 is true many times in my code, so I use pointers to functions.
void do_func(bool b64) {
typedef int (*pfunc32)(int);
typedef int (*pfunc64)(__int64);
pfunc32 call_func;
if (b64)
call_func = func64; //error C2440: '=' : cannot convert from 'int (__cdecl *)(__int64)' to 'pfunc32'
else
call_func = func32;
//...
call_func(6);
}
How can I avoid this error and cast call_func to pfunc32 or pfunc64?
The language requires all functions called through the same function pointer to have the same prototype.
Depending on what you want to achieve, you could use the pointer/cast aproach already mentioned (which satisfies this requirement at the loss of type safety) or pass a union instead:
union u32_64
{
__int64 i64;
int i32;
};
int func64(union u32_64 a) {
return (int) a.i64/2;
}
int func32(union u32_64 a) {
return --a.i32;
}
void do_func(bool b64) {
typedef int (*pfunc)(union u32_64);
pfunc call_func;
if (b64)
call_func = func64;
else
call_func = func32;
//...
union u32_64 u = { .i64 = 6 };
call_func(u);
}
Pass a void pointer and cast it in the function body.
Of course this means less compiler control if you use the wrong type; if you call func64 and pass an int to it the program will compile and produce wrong results without giving you any tip of what is going wrong.
int func64(void *a) {
__int64 b = *((__int64*) a);
return (int) b/2;
}
int func32(void *a) {
int b = *((int *) a)
return b-1;
}
I need to call func32() or func64() depending on flag b64
So do that:
void do_func(bool b64) {
if (b64)
func64(6);
else
func32(6);
}
Well, first of all, please note that function func32 is returning the input argument as is.
This is because with return a--, you are returning the value of a before decrementing it.
Perhaps you meant to return a-1 instead?
In any case, you can simply declare this function as int func32(__int64 a).
This way, it will have the same prototype as function func64, but will work exactly as before.
BTW, calling a function through a pointer might be more "expensive" than a simple branch operation, so depending on your application, you might be better off with a simple if/else conditional statement...
Make a wrapper for func64:
int func64_as_32(int a) {
return func64(a);
}
Now you can assign either func32 or func64_as_32 to call_func since they have the same signature. The value you pass in, 6, has type int so passing it to func64_as_32 has the same effect as passing it directly to func64.
If you have call sites where you pass in a value of type __int64 then you'd do it the other way around, wrap func32.
As bool in C++ converts to int ( true => 1, false => 0 ) you can use b64 as array index. So take SJuan76's advice, convert your functions prototype to int f(void*) and put them into array int (*array_fun[2])(void* x); . You can call these functions then like that :
int p = 6;
array_fun[b64](&p);
void xGetFunctionAddress(void* FunctionDefinition, std::string FunctionName)
{
*static_cast<FARPROC*>(FunctionDefinition) = xProcAddress(Module, FunctionName.c_str());
}
In the above code, I'm trying to get rid of that FARPROC* to make it cross-platform. However, if I cast to long long int (*)(), it gives me the error that it cannot statically cast to that. So when I typedef it, it works:
Ex:
//This works:
void xGetFunctionAddress(void* FunctionDefinition, std::string FunctionName)
{
typedef __stdcall long long int (*Ptr)();
*static_cast<Ptr*>(FunctionDefinition) = GetProcAddress(Module, FunctionName.c_str());
}
//This doesn't:
void xGetFunctionAddress(void* FunctionDefinition, std::string FunctionName)
{
*static_cast<long long int(*)()>(FunctionDefinition) = GetProcAddress(Module, FunctionName.c_str());
}
What am I doing wrong in the second example? :S
Your are casting the void pointer to a function pointer and then dereferencing it. This evaluates to an assignment to a function instead of a function pointer. The following should take of the problem
*static_cast<long long int(__stdcall **)()>(FunctionDefinition) = GetProcAddress(Module, FunctionName.c_str());
^^
Notice the additional pointer level next to __stdcall.
It would be useful to see the specific error message, but it looks like you might be missing the __stdcall dcl-specifier in your static_cast. Does it work if you add that?
Edit:
Looking further, it appears this may not be supported. Please see this answer: https://stackoverflow.com/a/1096349/279130 which seems to address the same question.
What is GetProcAddress() defined to return?
If it's a void *, you can't portably cast that to a function pointer. See https://stackoverflow.com/a/1096349/37386