Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust: Unreachable code query #17525

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Rust: Unreachable code query #17525

wants to merge 6 commits into from

Conversation

geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Sep 19, 2024

Unreachable code query for Rust.

@paldepind please would you review, particularly whether the logic in firstUnreachable and skipNode is reasonable and written as cleanly as possible right now; and whether there are obvious explanations for the false positive results in the test?

@geoffw0 geoffw0 added no-change-note-required This PR does not need a change note Rust Pull requests that update Rust code labels Sep 19, 2024
Copy link
Contributor

QHelp previews:

rust/ql/src/queries/unusedentities/UnreachableCode.qhelp

Unreachable code

This rule finds code that is never reached. Unused code should be removed to increase readability and avoid confusion.

Recommendation

Remove any unreachable code.

Example

In the following example, the final return statement can never be reached:

fn fib(input: u32) -> u32 {
	if (input == 0) {
		return 0;
	} else if (input == 1) {
		return 1;
	} else {
		return fib(input - 1) + fib(input - 2);
	}

	return input; // BAD: this code is never reached
}

The problem can be fixed simply by removing the unreachable code:

fn fib(input: u32) -> u32 {
	if (input == 0) {
		return 0;
	} else if (input == 1) {
		return 1;
	} else {
		return fib(input - 1) + fib(input - 2);
	}
}

References

@geoffw0 geoffw0 added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Sep 20, 2024
Copy link
Contributor

@subatoi subatoi left a comment

Choose a reason for hiding this comment

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

👍 LGTM

Copy link
Contributor

@aibaars aibaars left a comment

Choose a reason for hiding this comment

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

This looks fine to me. However, it may be worth fixing some of the missing CFG steps instead of marking a lot of false results in the expected output. By the looks of it they are mainly caused by the lack of special handling of boolean literals. I updated the branch to pull in the latest CFG improvements, with a bit of luck some of the issues have already been fixed.

@aibaars
Copy link
Contributor

aibaars commented Sep 27, 2024

@hvitved Could you have a quick look at this too?

* Holds if `n` is an AST node that's unreachable, and is not the successor
* of an unreachable node (which would be a duplicate result).
*/
predicate firstUnreachable(AstNode n) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be better to base this on the resulting CFG, as that can take things like splitting into account (if we implement that). For example, it would be able to identify

if (x) {
  ...
  if (!x) {
   // dead
  }
}

The CFG construction only assigns CFG nodes to AST nodes that are actually reachable, so it would be something like

private predicate unreachable(AstNode n) {
  not n = any(CfgNode cfn).getAstNode()
)

private predicate firstUnreachable(AstNode n) {
  unreachable(n) and
  (
    not ControlFlowGraphImpl::succ(_, n, _)
    or
    exists(AstNode pred |
      ControlFlowGraphImpl::succ(pred, n, _) and
      not unreachable(pred)
    )
  )
)


fn unreachable_if() {
if false {
do_something(); // BAD: unreachable code [NOT DETECTED]
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be fixed by #17602.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation no-change-note-required This PR does not need a change note ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. Rust Pull requests that update Rust code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants