Unexpected compiler error (Superfluous Cast?) - casting

I'm currently in the process of writing my own kernel bottom up, and I've come across this little issue in my linear memory manager, that I can't seem to understand.
I've got the following piece of code;
void* end_page_address = /*(void*)*/ 0x3FF000;
However, when the void pointer cast is disabled, I get the following error by g++;
src/paging/LinearMemoryManager.cpp: In constructor 'LinearMemoryManager::LinearMemoryManager(PhysicalMemoryManager*)':
src/paging/LinearMemoryManager.cpp:87:42: error: invalid conversion from 'int' to 'void*' [-fpermissive]
How come? - Because it's apparently not generally needed, as the line just above it compiles just fine without a cast:
void* start_page_address = 0x00000000;

I think that the NULL pointer, which has address 0, (even written as 0x00000 or similar), deserves a specific treatment in the C++ specification (and inside the GCC compiler). BTW, C++11 added nullptr and its type with good reasons.
But non-zero addresses like void* end_page_address = (void*) 0x3FF000; need an explicit cast.
I hope you are aware of C++ tricks (exceptions, constructors, RTTI, ...) when coding a kernel with it. You might need to understand exactly how your particular version of g++ handles them.
I also hope your kernel is free software (GPL-ed), and that you follow the "release early, release often" motto. I'll be curious to look inside its source code.

Related

Trigger a compiler error when trying to add char* to int?

C++ compilers happily compiles this code, with no warning:
int ival = 8;
const char *strval = "x";
const char *badresult = ival + strval;
Here we add a char* pointer value (strval) to an int value (ival) and store the result in a char* pointer (badresult). Of course, the content of the badresult will be total garbage and the app might crash on this line or later when it is trying to use the badresult elsewhere.
The problem is that it is very easy to make such mistakes in real life. The one I caught in my code looked like this:
message += port + "\n";
(where message is a string type handling the result with its operator += function; port is an int and \n is obviously a const char pointer).
Is there any way to disable this kind of behavior and trigger an error at compile time?
I don't see any normal use case for adding char* to int and I would like a solution to prevent this kind of mistakes in my large code base.
When using classes, we can create private operators and use the explicit keyword to disable unneeded conversions/casts, however now we are talking about basic types (char* and int).
One solutions is to use clang as that has a flag to enable warning for this.
However I can't use clang, so I am seeking for a solution that triggers a compiler error (some kind of operator overload or mangling with some defines to prevent such constructs or any other idea).
Is there any way to disable this kind of behavior and trigger an error at compile time?
Not in general, because your code is very similar to the following, legitimate, code:
int ival = 3;
const char *strval = "abcd";
const char *goodresult = ival + strval;
Here goodresult is pointing to the last letter d of strval.
BTW, on Linux, getpid(2) is known to return a positive integer. So you could imagine:
int ival = (getpid()>=0)?3:1000;
const char *strval = "abcd";
const char *goodresult = ival + strval;
which is morally the same as the previous example (so we humans know that ival is always 3). But teaching the compiler that getpid() does not return a negative value is tricky in practice (the return type pid_t of getpid is some signed integer, and has to be signed to be usable by fork(2), which could give -1). And you could imagine more weird examples!
You want compile-time detection of buffer overflow (or more generally of undefined behavior), and in general that is equivalent to the halting problem (it is an unsolvable problem). So it is impossible in general.
Of course, one could claim that a clever compiler could warn for your particular case, but then there is a concern about what cases should be useful to warn.
You might try some static source program analysis tools, perhaps Clang static analyzer or Frama-C (with its recent Frama-C++ variant) - or some costly proprietary tools like Coverity and many others. These tools don't detect all errors statically and takes much more time to execute than an optimizing compiler.
You could (for example) write your own GCC plugin to detect such mistakes (that means developing your own static source code analyzer). You'll spend months in writing it. Are you sure it is worth the effort?
However I can't use clang,
Why? You could ask permission to use the clang static analyzer (or some other one), during development (not for production). If your manager refuses that, it becomes a management problem, not a technical one.
I don't see any normal use case for adding char* to int
You need more imagination. Think of something like
puts("non-empty" + (isempty(x)?4:0));
Ok that is not very readable code, but it is legitimate. In the previous century, when memory was costly, some people used to code that way.
Today you'll code perhaps
if (isempty(x))
puts("empty");
else
puts("non-empty")
and the cute thing is that a clever compiler could probably optimize the later into the equivalent of former (according to the as-if rule).
No way. It is valid syntax, and very useful in many cases.
Just think about you were to write int b=a+10 but you wrote int b=a+00 incorrectly, the compiler won't know it is an error by mistake.
However, you can consider to use C++ classes. Most C++ classes are well designed to prevent such obvious mistakes.
In the first example in your question, really, compilers should issue a warning. Compilers can trivially see that the addition resolves to 8 + "x" and clang does indeed optimise it to a constant. I see the fact it doesn't warn about this as a compiler bug. Although compilers are not required to warn about this, clang goes through great efforts to provide useful diagnostics, and it would be an improvement to diagnose this as well.
In the second example, as Matteo Italia pointed out, clang does already provide a warning option for this, enabled by default: -Wstring-plus-int. You can turn specific warnings into errors by using -Werror=<warning-option>, so in this case -Werror=string-plus-int.

C++ Why do we need to explicitly cast from one type to another?

I was writing some code recently and found myself doing a lot of c-style casts, such as the following:
Client* client = (Client*)GetWindowLong(hWnd, GWL_USERDATA);
I thought to myself; why do we actually need to do these?
I can somewhat understand why this would be needed in circumstances where there is lot of code where the compiler may not what types can be converted to what, such as when using reflection.
but when casting from a long to a pointer where both types are of the same size, I don't understand why the compiler would not allow us to do this?
when casting from a long to a pointer where both types are of the same size, I don't understand why the compiler would not allow us to do this?
Ironically, this is the place where compiler's intervention is most important!
In vast majority of situations, converting between long and a pointer is a programming error which you don't want to go unnoticed, even if your platform allows it.
For example, when you write this
unsigned long *ptr = getLongPtr();
unsigned long val = ptr; // Probably an error
it is almost a certainty that you are missing an asterisk in front of ptr:
unsigned long val = *ptr; // This is what it should be
Finding errors like this without compiler's help is very hard, hence the compiler wants you to tell it that you know when you are doing on conversions like that.
Moreover, something that is fine on one platform may not work on other platforms. For example, an integral type and a pointer may have the same size on 32-bit platforms, but have different sizes on 64-bit platform. If you want to maintain any degree of portability, the compiler should warn you of the conversion even on the 32-bit platform, where the sizes are identical. Compiler warning will help you identify an error, and switch to a portable pointer-as-integer type intptr_t.
I think the idea is that we want compiler to tell us when we are doing something dodgy and/or potentially unintended. That way we don't do it by accident. So the compiler complains unless we explicitly tell the compiler that this is what we really, really want. We do that by using the a cast.
Edited to add:
It might be better to ask why we are allowed to cast between types. Originally C was created as a strongly typed language. Although it allows promotion/conversion between related object types (like between ints and floats) it is supposed to prevent access and assignment to the wrong type as a language feature, a safety measure. However occasionally this is useful so casting was put in the language to allow us to circumvent the type rules on those occasions when we need to.

compiler warnings about type punning in gcc

I have a large program that has a large number of fragments of the form
float t = amplitudes->read(current_element);
if ( *((uint32_t * ) &t) == 0xsomereservedvalue)
do_something
else
do_something_else
This compiles fine with gcc 3.4.x no warnings. Compiled with -Wtrict-aliasing=2 still no warnings. I recently tried compiling with gcc4.4 and got a vast number of warnings about type punned references. Can someone tell me is there any reasonable situation under which this sort of code can fail? As far as I can see, type punning is only a potential issue if optimizations arrange things such that something might be written back from a register after another line of code reads it, which since we're on the return of a function here simply can't happen. Am I missing something here, or is gcc being somewhat braindead?
Of course it warns. I just checked gcc 4.8.2 it warns too. Imagine, that float size for target machine is 16 bit and you are trying to read 32 bits after data bounds. It is UB.
btw I disagree with reinterpret_cast usage in this case. The only useful way for reinterpret_cast is *(reinterpret_cast<char *>(&t)), even *(reinterpret_cast<unsigned *>(&t)) will still break aliasing rules, and you'll get the same warning. That is because compiler only knows in C++ that char is smallest so every type might be casted to it.
GCC have an attribute to tell that given type may alias. It is not so easy to use it as well.
unsigned * __attribute__ ((__may_alias__)) pu = (unsigned *) &t;
if (*pu == 0xsomereservedvalue)
do_something ();
else
do_something_else ();
But here things at least make sense. We are asking for aliasable pointer. Cost: code is not portable now.
So after all considerations, I recommend just supply -fno-strict-aliasing option if you really sure that you are know what you do.
The “dereferencing type-punned pointer will break strict aliasing” tells you that the compiler may be making optimizations that may break your code.
The reason why this might happen is that the compiler is allowed (according to the language spec) to assume that that you will only access an array with its own type or a char type.
To a guarantee of correctness one must -either use memcpy when type punning or build with strict aliasing disabled. (Unions are a bit unclear)
Take a look here for another more detailed posting on strict aliasing.

Disabling "cast from pointer to smaller type uint32_t" error in Clang

I'm working on a school project that involves porting a large piece of C++ code on an experimental piece of hardware. Unfortunately, that hardware is 64-bit and the code contains many instances of pointer arithmetic that expects pointers to be 32-bit, i.e. it often does reinterpret_cast<uint32_t>(ptr).
Going through them one by one would be very tedious and since this is an experimental project anyway, I'm happy to settle for a "hackish" workaround. So instead I modified the implementation of malloc to ensure it never allocates memory above the 4GB limit. Technically, these casts should therefore be valid.
Question is, how do I explain this to Clang? The error I'm getting is: error: cast from pointer to smaller type 'uint32_t' (aka 'unsigned int') loses information. Is there a way to disable it?
Thanks,
David
I was able to disable this with -fms-extensions after getting this from someone on the Cpplang Slack:
Looking at "DiagnosticSemaKinds.td" it shows up as err_bad_reinterpret_cast_small_int, https://github.com/llvm-mirror/clang/blob/release_50/include/clang/Basic/DiagnosticSemaKinds.td#L6193
There are two occurences in "SemaCast.cpp" -- one of which suggests it's sensitive to MS extensions, https://github.com/llvm-mirror/clang/blob/release_50/lib/Sema/SemaCast.cpp#L2112
One could try -fms-extensions (hopefully not -fms-compatibility), but that would bring all the shebang with it.
I agree that you should bite the bullet and fix the code to use the correct integer type. But to answer your question: No, you can't disable it, though you can work around it.
Many errors come from warnings. A good thing in general, but if you want to disable the warning, just do it. Since the culprit is probably something like -Wall which enables many warnings you should keep on, you should selectively disable this single warning. The error message mentions the diagnostic responsible for error message, e.g. ... [-Wextra-tokens] (if it doesn't, remove the -fno-diagnostics-show-option flag). You can then disable this diagnostic completely by adding -Wno-extra-tokens (again, the "extra tokens" warning is an example), or turn it into a non-fatal warning by means of -Wno-error=extra-tokens.
However, this specific error is not due to a warning and I can't find any option to disable errors (makes sense, since most errors are fatal).
But to just truncate the integer value and not having to fix all the wrong uses of uint32_t just yet, you could use static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr)). Needless to say, this will still be wrong.
how about using uintptr_t, most of your pointer arithmetic may still works.
Save this piece of code as mycast.hpp and add -include mycast.hpp to your Makefile.
#include <cstdint>
template<typename U, typename T>
U Reinterpret_cast(T *x) {
return (U)(uintptr_t)x;
}
template<typename U, typename T>
U Reinterpret_cast(T &x) {
return *(U*)&x;
}
#define reinterpret_cast Reinterpret_cast
They should do their job unless your code is too tricky.
Your strategy will not work for stack-allocated objects, be careful!! You can insert some debugging/logging logic to Reinterpret_cast if necessary.
I hit this same problem in a project without C++11, and worked around it like this:
inline int PtrToInt(void* ptr)
{
void* clang[1];
clang[0] = ptr;
return *(int*)clang;
}

How to address C4191 warning around calls to GetProcAddress with FARPROC?

Recently I tried to use /Wall Visual C++ option to enable all warnings and found that the following code:
typedef BOOL ( WINAPI * TIsWow64ProcessFunction )( HANDLE, BOOL* );
TIsWow64ProcessFunction isWow64ProcessFunction = reinterpret_cast<TIsWow64ProcessFunction> (
::GetProcAddress( kernel32DllHandle, "IsWow64Process" ) );
spawned C4191:
warning C4191: 'reinterpret_cast' : unsafe conversion from 'FARPROC' to 'TIsWow64ProcessFunction'
Calling this function through the result pointer may cause your program to fail
If I use a C-style cast the same warning appears but now it mentions "type cast" instead of "reinterpret_cast".
The same warning is repeated for just any case I call GetProcAddress() and convert its return value to some usable function pointer.
How do I address these warnings? Do I need to make alterations to my code?
You are casting a FARPROC (function pointer with no args) to a function pointer with args. Normally this is a hugely dumb thing to do that will probably result in stack corruption.
Now it turns out that GetProcAddress() doesn't really return a FARPROC and you do actually know what you're doing -- but the compiler doesn't know that and it feels obliged to warn you.
The only way you can silence it is using a #pragma or a compiler switch to turn off the warning. It is ugly and messy, but that is Windows programming for you. :-)
As other answers have already mentioned, this is a useful warning. Normally, this type of coercion would be a serious bug hiding in your application.
Therefore, you probably don't want to disable it globally with a compiler switch. Yet you still need to call GetProcAddress, and you like your builds to compile cleanly without warnings.
You have two good options:
Suppress each individual warning using an MSVC-specific pragma. In a new line just above the maligned cast, add the following code:
#pragma warning(suppress: 4191)
This suppresses the warning for the very next line of code only, ensuring that it is not globally suppressed and you'll still get a warning if you try to do something stupid elsewhere in the code base. Of course, you'll need to add this each time you use GetProcAddress, which is kind of a pain. Worse yet, it's a non-portable, MSVC-specific extension that uglifies your code.
So, alternatively…
You can silence the warning by explicitly casting the result of GetProcAddress (a FARPROC) to void*, and then casting that void* to the specific function-pointer type. For example:
typedef BOOL ( __stdcall *TIsWow64ProcessFunction )( HANDLE, BOOL* );
TIsWow64ProcessFunction isWow64ProcessFunction =
reinterpret_cast<TIsWow64ProcessFunction>(
reinterpret_cast<void*>(
::GetProcAddress(hInstance, "IsWow64Process")));
This approach will work with other compilers, is slightly less ugly, and is arguably more semantically meaningful.
Basically the compiler cannot guarantee that the function is of the appropriate type, so it's unsafe for you to call the resulting pointer. However, in a VS program you don't have to link or load against the Windows .dlls explicitly, they will be loaded for you and any function in the Windows header is always available to use.
I was bothered also by these warnings as I use this sort of thing quite often. I liked #Cody Gray's answer as it suppresses the warning only at the point of use but doesn't filter out other possibly valid warnings.
I made a simple function_cast helper to make it a bit more c++ like:
template<typename Result, typename Original>
Result function_cast(Original fptr)
{
return reinterpret_cast<Result>(reinterpret_cast<void *>(fptr));
}
The OP's code becomes:
auto isWow64ProcessFunction = function_cast<TIsWow64ProcessFunction>(::GetProcAddress( kernel32DllHandle, "IsWow64Process" ) );