Skip to content

C++: Fix some FPs in cpp/invalid-pointer-deref #12961

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

MathiasVP
Copy link
Contributor

@MathiasVP MathiasVP commented Apr 27, 2023

This fixes the FPs I added in #12953. The query is designed to search for patterns such as:

int* p = malloc(n);
int q = p + n;
...
use(*q);

but by marking any PointerArithmeticInstructions as a sink (or rather: anything that upper bounds a PointerArithmeticInstruction) we get too much flow (as illustrated in #12953). So this PR restricts the sinks to only the PointerArithmeticInstruction such that:

  • The operation appears on the right-hand side of a store (which is what the query always intended to do). After this store, we do a simple global dataflow to find the place where the value is dereferenced (as the query already does), or
  • the operation is directly loaded from. This would constitute an immediate out-of-bounds dereference and we don't need to search for a StoreInstruction.

@MathiasVP MathiasVP requested a review from a team as a code owner April 27, 2023 19:58
@github-actions github-actions bot added the C++ label Apr 27, 2023
@MathiasVP MathiasVP force-pushed the fix-fp-in-invalid-deref branch from 8f784d8 to e38f61d Compare April 28, 2023 10:16
@MathiasVP
Copy link
Contributor Author

MathiasVP commented Apr 28, 2023

Force-pushed a rebase to resolve the testcase conflicts after merging #12960.

There are some lost results. I'll investigate if they are the FPs (and are represented well by our tests).

Copy link
Contributor

@jketema jketema 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 sensible, but I have a very hard time understanding why this solves the referenced FPs. If I, for example, look at:

void test15(unsigned index) {
  unsigned size = index + 13;
  if(size < index) {
    return;
  }
  int* newname = new int[size];
  newname[index] = 0; // GOOD [FALSE POSITIVE]
}

There is exactly one PointerAdd in the IR and that is used in a Store. So it seems this should not be a case that is ruled out by this PR, yet the FP disappears.

iTo.(ConvertInstruction).getUnary() = iFrom or
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom or
// it's fine to treat pointer arithmetic as conversions as conversions
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// it's fine to treat pointer arithmetic as conversions as conversions
// it's fine to treat pointer arithmetic as conversions

@MathiasVP
Copy link
Contributor Author

There is exactly one PointerAdd in the IR and that is used in a Store. So it seems this should not be a case that is ruled out by this PR, yet the FP disappears.

But that PointerAdd is not flowing into the value of a store, instead, it's flowing into the store address 🙂.

@jketema
Copy link
Contributor

jketema commented May 1, 2023

But that PointerAdd is not flowing into the value of a store, instead, it's flowing into the store address 🙂.

My understanding of what the query is supposed to do is that were are actually only interested in the addresses from with we load and store, so this only adds to my confusion. Why would we look at all at values being stored?

@MathiasVP
Copy link
Contributor Author

After sleeping on this I realized that you're right, @jketema. The query really shouldn't need to deal with this. The motivation for this PR was to remove FPs like:

void test15(unsigned index) {
  unsigned size = index + 13;
  if(size >= index) {
    int* newname = new int[size];
    newname[index] = 0; // GOOD [FALSE POSITIVE]
  }
}

like we discussed above, this FP is removed because newname[index] is neither the right-hand side of a StoreInstruction, nor is it directly loaded from. However, it turns out that the root cause of this issue is that the size >= index guard makes the range-analysis library think that size >= index, even though size >= index + 13 is a much more precise bound.

I'll pull this PR into a draft state while we discuss how to solve this problem.

@MathiasVP MathiasVP marked this pull request as draft May 2, 2023 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants