VS11 Code Analysis Hints? - c++

I got a lot of false positives when running the code analysis for C++ in VS11. For example i have a few dozen switch and it says my pointer may be null. All the cases in the switch (at least in one case) the pointer is set and the default calls my function which throws an assert(0) and exception. I guess since the assert and exception is in a method it doesn't realize its impossible for the pointer to be null. How do i hint or fix it so a false positive like this doesn't show up?

try using _Analysis_assume_(FALSE) in the switch, it hints unreachable code to the compiler.
You can also decorate functions that throw and don't return with _Analysis_noreturn_.

If the method invoked by the default case doesn't return anything, you can try making it return a "fake" null value that will be assigned to the pointer in the default case.
Type* MyClass::methodCalledInDefaultCase()
{
pointer = 0;
assert(0);
throw Exception;
return 0; // Hope this doesn't cause unreachable code warning
}
void MyClass::myMethod()
{
pointer = 0;
switch(whatever)
{
case foo:
...
case bar:
....
default:
pointer = methodCalledInDefaultCase();
break;
}
}
Hope this helps.

Related

How to tell Visual Studio's static analyzer that a function validates a precondition?

I have to admit I appreciate the effort the Visual Studio static code analyzer does. It has found some issues in my C/C++ code that could, under certain circumstances, lead to some unusual bugs.
However, there are some other places where it finds issues that I have already prepared for.
Take for instance something like this: I have a C array, with a static size somewhere:
static const int DataSize = 100;
int Data[DataSize];
...and then I have a method or function that accesses this data:
void DoSomething(size_t index)
{
if (index >= DataSize)
Panic("Out of bounds");
Data[index] = DoSomethingElse();
}
This Panic() function is meant to notify me when the precondition is not met, and points to an error that can't be recovered from. In a debug build, it breaks into the debugger so I can analyze what happened, while in a release build, it will intentionally crash the program, leaving some useful debug information.
However, if I compile this, Visual Studio 2019 gives me the following warning:
Warning C6386: Buffer overrun while writing to 'Data': the writable size is '400' bytes, but 'index' bytes might be written.
The warning is indeed valid, if I were not performing the precondition check just before.
One way to suppress this warning is by changing the code to something like:
void DoSomething(size_t index)
{
if (index >= DataSize)
{
Panic("Out of bounds");
return; // This is never reached...
}
Data[index] = DoSomethingElse();
}
But, not only this is unnecessarily verbose, it also may confuse the static code analyzer even more, because it can make it think that returning is a valid code path, further confusing it.
Another example, this time unrelated to arrays, and applicable to C and C++. Consider a function or method like this:
int DoSomeOperation(int operationType, int value)
{
int foo;
switch (operationType)
{
case 0:
foo = 10;
break;
case 1:
foo = value + 1;
break;
case 2:
foo = value - 1;
break;
// ... many more cases
default:
Panic("Invalid operationType");
// We never reach this line...
}
DoSomeOtherOperation(foo);
}
This raises the following warning in the DoSomeOtherOperation() line:
Warning C6001: Using uninitialized memory 'foo'.
Once again, I can either explicitly initialize foo, initialize it to something in the default case, or return from the function after Panic(), but technically, neither is necessary, since for all semantically valid values of operationType, foo is indeed initialized.
In fact, I might prefer to leave foo uninitialized at the beginning, so the static analyzer -does- catch a case where I did indeed missed the initialization.
Now, is there a way to annotate the Panic function, so the static code analyzer knows that this function will validate the precondition, or alternatively, that it terminates the program in all cases, so it doesn't have to consider the case where the function returns and the program continues?
I am not aware of any way to tell the analyzer that a parameter is checked in the code but isn't this a job exactly for the In_range(low, hi) annotation?
Change the declaration to the following and the analyzer should be able to check the precondition (So long as it picks up the values of static like DataSize in this example, I am not sure whether it does or not).
void DoSomething(_In_range_(0, DataSize)
SAL is described at
https://learn.microsoft.com/en-us/cpp/code-quality/using-sal-annotations-to-reduce-c-cpp-code-defects?view=msvc-160

What is the correct way to return an 'Invalid Value' type in C++, without the use of pointers?

I often use -1 as the invalid value type when returning from a function, where the input yields incorrect output. For instance, writing an indexing function where the index is out of bounds, instead of throwing an exception, -1 can be returned. But when writing a function that has negative values as possible return types, this technique does not work. What is the correct way to return an invalid type value in such instances?
The technique I use mostly is to set the return type to be of type *int, and return a Pointer to NULL. But, that requires all return values to be of a pointer type, which seems like an extra overhead to the function. Is there an accepted standard for returning values in such cases?
In newer C++, I'd suggest using std::optional<>; if you don't yet have it, boost::optional<>.
One option would be to let your function take a bool& as an output parameter used to indicate if the returned value is valid.
int myFunc(bool& valid); // sets 'valid' to true if result is usable, false otherwise
Users can then do
bool valid = false;
Int result = myFunc(valid);
if (!valid) {
// Handle error
}
// Use result
Not the most pretty solution, but it does the job.
Apart from the answer I provided above, there's a very clean, continuation-passing solution (given you're non-virtual):
template<typename Success, typename Failed>
void parse( const std::string& str, Success s, Failed f )
{
auto a = start_parse(str);
if( a.problem() )
return f(); // you _might_ have an error code here
s( finish_parse(str, a) );
}
Then you might customize by:
Success:
[&i] (int i_) { i = i_; }
out(i), where out(int& output_) returns the above lambda for output_
actual code doing something useful
function to continue with
Failed:
[&i]{ i = 0; }, `[&i]{ i = nullopt; }, or any other default value
[] { throw MyFavouriteException(); }
retry logic
std::terminate()
[]{} if you don't care (or if you're 100% sure it'll succeed)
It might look a little verbose, but IMHO:
it's trivial to read
any other schematics can be mimicked, even if there's no default c'tor
easy to change as well
'you don't pay for what you don't use', can surely be optimized away
every schematic is visible and apparent from code:
for default value, caller sets it, not callee or global
std::optional<> and default value are handled the same
for exception, caller knows better what to throw
for no action, you don't have to lookup the implementation to know this
for std::terminate(), well, you know what to expect
if you 'speak' CPS, you might actually continue and save an if / catch / etc.
The only issue I see is constructor initializer lists. Any thoughts on this?

Function reference and assert(0) in C++

I wish to understand what fetch().text and assert(0) do below. I am not familiar with a function like fetch() that can refers to a member of the return type, i.e. fetch().text. Is this somehow enabled by the use of assert(0)?
class SimpleS{
struct internal_element {
const char *text;
};
class SimpleE {
public:
SimpleE() {
}
const char* text() const {
return fetch().text;
}
void set_text(const char *text) {
fetch().text = text;
}
private:
internal_element& fetch() const {
... // some code
assert(0);
}
}
The assertion has nothing to do with it. What's happening here is that fetch() returns a reference to an internal_element. That enables you to refer to members of that struct in the returned value:
fetch().text
refers to the internal_element::text member of the internal_element object returned by fetch().
As to why there's an assert(0) in there, no idea. You didn't give us the code. Usually, when a function ends with such an assert is because the programmer wants to catch cases where he didn't cover some possibility. For example:
if (condition)
//...
else if (condition)
//...
// We should have covered all possible conditions above and already
// returned. If we actually get here, then we did something wrong.
assert(0);
The assert(0); will always fail. I suppose its purpose is to make sure that this method is never called in the first place.
(Assuming, of course, there is no condition for the assert(0); being run)
If the ... // some code in your code has a conditional return, assert(0) will never be called. assert(0) basically causes an exception and the program will die if the exception is not being caught in the calling function.
return fetch().text
calls the function fetch. This presumably returns an object of class internal_element. It then accesses the text member of this returned object and returns it. It's effectively equivalen to:
internal_element temp = fetch();
return temp.text;
In below code (which you shared), programmer got condition which make function return, thats what the // some code supposed to do...but if one of the the conditions is not true (and it return) control reaches end of function it means there is fatal error, so is the purpose of assert(0) at the end of function...
internal_element& fetch() const {
... // some code
assert(0);
}

Can I tell the compiler to consider a control path closed with regards to return value?

Say I have the following function:
Thingy& getThingy(int id)
{
for ( int i = 0; i < something(); ++i )
{
// normal execution guarantees that the Thingy we're looking for exists
if ( thingyArray[i].id == id )
return thingyArray[i];
}
// If we got this far, then something went horribly wrong and we can't recover.
// This function terminates the program.
fatalError("The sky is falling!");
// Execution will never reach this point.
}
Compilers will typically complain at this, saying that "not all control paths return a value". Which is technically true, but the control paths that don't return a value abort the program before the function ends, and are therefore semantically correct. Is there a way to tell the compiler (VS2010 in my case, but I'm curious about others as well) that a certain control path is to be ignored for the purposes of this check, without suppressing the warning completely or returning a nonsensical dummy value at the end of the function?
You can annotate the function fatalError (its declaration) to let the compiler know it will never return.
In C++11, this would be something like:
[[noreturn]] void fatalError(std::string const&);
Pre C++11, you have compiler specific attributes, such as GCC's:
void fatalError(std::string const&) __attribute__((noreturn));
or Visual Studio's:
__declspec(noreturn) void fatalError(std::string const&);
Why don't you throw an exception? That would solve the problem and it would force the calling method to deal with the exception.
If you did manage to haggle the warning out some way or other, you are still left with having to do something with the function that calls getThingy(). What happens when getThingy() fails? How will the caller know? What you have here is an exception (conceptually) and your design should reflect that.
You can use a run time assertion in lieu of your fatalError routine. This would just look like:
Thingy& getThingy(int id)
{
for ( int i = 0; i < something(); ++i )
{
if ( thingyArray[i].id == id )
return thingyArray[i];
}
// Clean up and error condition reporting go here.
assert(false);
}

Why "not all control paths return a value" is warning and not an error?

I was trying to answer this question. As suggested by the accepted answer, the problem with that code is that not all control paths are returning a value. I tried this code on the VC9 compiler and it gave me a warning about the same. My question is why is just a warning and not an error? Also, in case the path which doesn't return a value gets executed, what will be returned by the function (It has to return something) ? Is it just whatever is there on top of the stack or is the dreaded undefined behavior again?
Failing to return a value from a function that has a non-void return type results in undefined behaviour, but is not a semantic error.
The reason for this, as far as I can determine, is largely historical.
C originally didn't have void and implicit int meant that most functions returned an int unless explicitly declared to return something else even if there was no intention to use the return value.
This means that a lot of functions returned an int but without explicitly setting a return value, but that was OK becase the callers would never use the return value for these functions.
Some functions did return a value, but used the implicit int because int was a suitable return type.
This means that pre-void code had lots of functions which nominally returned int but which could be declared to return void and lots of other functions that should return an int with no clear way to tell the difference. Enforcing return on all code paths of all non-void functions at any stage would break legacy code.
There is also the argument that some code paths in a function may be unreachable but this may not be easy to determine from a simple static analysis so why enforce an unnecessary return?
I would guess it is only a warning because the compiler cannot always be 100% sure it is possible to not hit a return.
i.e. if you had:
-= source1.c =-
int func()
{
if(doSomething())
{
return 0;
}
}
-= source2.c =-
int doSomething()
{
return 1;
}
The compiler in this case might not be able to know it will always hit the return, but you do. Of course this is terrible programming practice to rely on knowing how external code works.
As for what will actually be returned it depends on the platform. On x86 ABIs EAX is used for the return value (up to 32bits) so it will return what ever was placed in that register (which could be a return from something else, a temporary value or total garbage).
Technically it is not guaranteed to be an error if you call a function and that function always throws an exception. For example here is some pseudo code, and you know raiseError always throws.
MyClass func( params )
{
if( allIsValid() )
{
return myObject;
}
else
{
raiseError( errorInfo );
}
}
If the compiler cannot see the implementation of raiseError, it will not know that the function is going to throw. So really there is actually no undefined behaviour here. Of course it is good to silence the compiler here, which you can do with either writing a "dummy" return statement after raiseError, or a dummy "throw". I call them "dummy" because they will never be reached in reality. (You can also suppress the warning if you really insist). However there is no error or undefined behaviour.
here is another reason it isn't an error
the following will give you the same warning since the compiler expects you to return something from the catch block even though you're throwing there
int foo(){
try{
return bar(0);
} catch(std::exception& ex){
//do cleanup
throw ex;
}
}
int bar(unsigned int i){
if(i == 0){
throw std::string("Value must be greater than 0");
} else{
return 0;
}
}
Another example where it may be okay for some control paths to not return a value:
enum E : int {A, B};
int foo(E e) {
switch (e) {
case A: return 30;
case B: return 50;
}
}
It's possible that e won't be A or B, but the implication is that it always will be one of those values. If that's the case then the code is fine and there's no problem. Making this warning into a mandatory error would require unnecessary, 'unreachable' clutter.
If you want the warning to be an error anyway, you can configure your compiler to do that with a flag like /WX or -Werror. Though of course you should note that different compilers may make different determinations as to what's unreachable so you may be fixing different things for different compilers.
It is not an error because it may be the intended behaviour. For example, some encryption libraries use uninitialized local data as a step for seeding. As return values are kept in calling-convention and platform specific locations, this may help in some unusual (like the above) situations. In this case, the function returns whatever is left on the register used to return the return value.
Consider the following scenario:
UINT GenderID(GENDER gender)
{
switch(gender)
{
case MALE:
return MALE_ID;
case FEMALE:
return FEMALE_ID;
}
// default not required because [GENDER] in our 'Matrix' CAN be either M or F
}
a C++ complier should let you have your 'Matrix' your way; Thus its not an Error.