Skip to content

New check for rethrow without current handled exception#3270

Merged
danmar merged 4 commits into
cppcheck-opensource:mainfrom
ntfshard:rethrowNoCurrentException
May 31, 2021
Merged

New check for rethrow without current handled exception#3270
danmar merged 4 commits into
cppcheck-opensource:mainfrom
ntfshard:rethrowNoCurrentException

Conversation

@ntfshard
Copy link
Copy Markdown
Contributor

This check should warn user about forgotten argument for throw. I guess it could be quite common in case if you go to look up the right type of exception or macro for it and got distracted or something.
Possible FP can be if rethrow which located inside a function which called from a catch block. But in this case it should be one place for entire project if code in not bad shape.

Standard references:

Also similar check presented in another analyzer: https://pvs-studio.com/en/docs/warnings/v667/

Copy link
Copy Markdown
Collaborator

@danmar danmar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this check. Have some small nits.

Comment thread lib/checkexceptionsafety.cpp Outdated
Comment thread lib/checkexceptionsafety.cpp
Comment thread lib/checkexceptionsafety.h Outdated
Comment thread lib/checkexceptionsafety.cpp Outdated
Comment thread test/testexceptionsafety.cpp Outdated
Comment thread lib/checkexceptionsafety.h Outdated
@danmar
Copy link
Copy Markdown
Collaborator

danmar commented May 23, 2021

I think it would be best to implement this with the CTU (Cross Translation Unit) analysis. Let me know if you want some intro for how that is done.

According to https://pvs-studio.com/en/docs/warnings/v667/ , no warning should be written here:

void rethrow() {
    throw;  // <- don't warn
}

void bar() {
    try {
        dostuff();
    } catch (...) {
        rethrow();
    }
}

@ntfshard
Copy link
Copy Markdown
Contributor Author

ntfshard commented May 23, 2021

I think it would be best to implement this with the CTU (Cross Translation Unit) analysis. Let me know if you want some intro for how that is done.

According to https://pvs-studio.com/en/docs/warnings/v667/ , no warning should be written here:

void rethrow() {
    throw;  // <- don't warn
}

void bar() {
    try {
        dostuff();
    } catch (...) {
        rethrow();
    }
}

Oh, I didn't know that Cppcheck has CTU functionality. It could help to avoid FP.
But I have 2 concerns about CTU check: performance and example from pvs site looks very synthetic. Throwing exceptions "too far" can lead to segfault even if code is valid (e.g. different runtimes, different compile options in 3rd party libraries)

@danmar
Copy link
Copy Markdown
Collaborator

danmar commented May 23, 2021

About performance; yes maybe it can be a problem. I don't know. We have a setting for how deep the ctu analysis is allowed to go. normally that setting will limit true positives but I guess in this case a low value could lead to false positives. well .. I hope that determining what functions are called from catch scopes shouldn't mean run time explodes too much.

Normally I would assume that catch scopes are pretty simple. Maybe some error message is logged. Some variable is assigned. Not much more than that usually. If we for instance determine that no catch scope in the analyzed code will call any functions then I feel it would be ok to write these warnings written by this checker. If there are function calls it would be good to avoid warnings in those functions that are called..

It is still possible there will be false positives if the code is a library for instance.. but this is probably ok.

@ntfshard
Copy link
Copy Markdown
Contributor Author

ntfshard commented May 24, 2021

Yeah, I expect same type of catch scopes. Anyway, to add CTU extra check I need some example. May be you can tell which check should I use as an example.

BTW, one more thing, if we have such hypothetical function with throw; what must be called only from catch block, what can guard it from the calling from other place of project? In other words, this function in a wrong context can terminate application. It's mostly like function with integer division which doesn't check divisor argument -- it could work fine, but can crash application.
But from other side we have "exception dispatcher" pattern https://isocpp.org/wiki/faq/exceptions#throw-without-an-object (just found)

Anyway, what's the plan?)

@danmar
Copy link
Copy Markdown
Collaborator

danmar commented May 24, 2021

Maybe you can test your checker with the tools/test-my-pr.py script. Then we get an idea about how much false positives there are..

Just checkout your branch and then run the script without arguments..

what can guard it from the calling from other place of project?

With my suggestion we would have a false negative there. But this should not affect many functions.

@ntfshard
Copy link
Copy Markdown
Contributor Author

my_check_diff.log

4 hits in 2 packages:

  • mapnik -- legit problem (twice)
  • me-tv, exception dispatcher idiom (twice)

I guess I could just add check for canonical style of this idiom: $func_scope_begin try { throw: } catch
It should be simple enough to avoid FP here and avoid using CTU analysis

@ntfshard ntfshard force-pushed the rethrowNoCurrentException branch from c53fd5f to 9c8fc2a Compare May 27, 2021 00:18
@ntfshard
Copy link
Copy Markdown
Contributor Author

my_check_diff.log
Reran with detection exception dispatcher, got 1 package with 3 hits in one file. All hits are legit

@danmar
Copy link
Copy Markdown
Collaborator

danmar commented May 30, 2021

Reran with detection exception dispatcher, got 1 package with 3 hits in one file. All hits are legit

ok sounds good. How do you determine that the hit is legit.. have you looked up all the catch scopes and determined that they don't execute the code? Or do you say so because the code looks dangerous.

I think technically we can merge this. But well.. I am still not 100% satisfied with the message. Somehow it sounds like we don't allow the exception dispatcher idiom. I believe your original message was better in that way. I just don't like to say "Calling" throw. I don't know if we can elaborate on your original message somehow.

Or maybe something like:

Rethrowing current exception with 'throw;', it seems there is no current exception to rethrow. If there is no current exception this calls std::terminate().

@ntfshard
Copy link
Copy Markdown
Contributor Author

ok sounds good. How do you determine that the hit is legit.. have you looked up all the catch scopes and determined that they don't execute the code? Or do you say so because the code looks dangerous.

The last one, it looks dangerous: it's a virtual methods with 2 lines of code: std::cerr<< "Not implemented"; and throw;
In previous result file, both hits in 2 different classes in ctors, when sqlite_open and sqlite3_prepare_v2 fails.

I just don't like to say "Calling" throw.

Yea, technically it's an expression and it should be evaluated, but it sounds much worse. It can be using instead of calling, but still not perfect enough. There are a bright side, it will be really rare message (2 of 512 projects) =)
I guess I can add a link https://isocpp.org/wiki/faq/exceptions#throw-without-an-object with more details in error message

@danmar danmar merged commit 06c4542 into cppcheck-opensource:main May 31, 2021
@ntfshard ntfshard deleted the rethrowNoCurrentException branch May 31, 2021 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants