Skip to content

Conversation

jbj
Copy link
Contributor

@jbj jbj commented Mar 20, 2020

This predicate replaces isChiForAllAliasedMemory, which was always intended to be temporary. A test is added to IRSanity.qll to verify that the new predicate corresponds exactly with (a fixed version of) the old one.

The implementation of the new predicate, Cached::hasConflatedMemoryResult in SSAConstruction.qll, is faster to compute than the old isChiForAllAliasedMemory because it uses information that's readily available during SSA construction.

EDIT: This PR now also contains a fix for how EntireAllocationMemoryLocation is modelled. There were cases before where InitializeParameterInstruction appeared to overwrite the result of AliasedDefinitionInstruction.

This predicate replaces `isChiForAllAliasedMemory`, which was always
intended to be temporary. A test is added to `IRSanity.qll` to verify
that the new predicate corresponds exactly with (a fixed version of) the
old one.

The implementation of the new predicate,
`Cached::hasConflatedMemoryResult` in `SSAConstruction.qll`, is faster
to compute than the old `isChiForAllAliasedMemory` because it uses
information that's readily available during SSA construction.
@jbj jbj added the C++ label Mar 20, 2020
@jbj jbj requested review from a team as code owners March 20, 2020 17:03
* as originating on the `AliasedDefinitionInstruction` at the entry of the
* function.
*/
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I modelled the naming of this predicate on isResultModeled, which is right above it.

It might be confusing that this predicate is inverted compared to isResultModeled: the new predicate holds when the instruction is imprecise, whereas isResultModeled holds when it's (in a sense) precise. Do we need isResultModeled? It's currently only used for the pretty-printer, and I think isResultConflated might be better for pretty-printing.

Copy link

Choose a reason for hiding this comment

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

I don't think there will be much use of isResultModeled. In fact, I believe that your usage is the first outside of the Instruction class itself.

I like having unmodeled results and operands print out as mu instead of m. I do think that isResultConflated is worth displaying in IR dumps as well, though. I'm not sure what punctuation to use for that, but Emoji open up a world of possibilities:
# 134| m134_4🔀(unknown) = Chi : total:m134_2, partial:m134_3

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Um... yes. I was thinking ma for results and operands that are conflated but not unmodelled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

...where the a is for Aliased.

or
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All the uses of InitializeNonLocal can hopefully just go away when we remove that opcode. That means this PR has a semantic conflict with @rdmarsh2's work.

Copy link

@dbartol dbartol 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 the approach. A few comments on the details.

@@ -65,6 +65,30 @@ private module Cached {
instruction instanceof ChiInstruction // Chis always have modeled results
}

cached
Copy link

Choose a reason for hiding this comment

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

In plain language, this predicate is basically identifying instructions that are either writing to all of aliased memory (AliasedDefinition, InitializeNonLocal, certain Chis and Phis), or are unmodeled, right? If so, I think it can be simplified:

  • If the memory location of the result of the old instruction totally overlaps AliasedVirtualVariable
  • If the instruction is a Chi, and the virtual variable of the result of the non-Chi old instruction is AliasedVirtualVariable.
  • If the result of the instruction is unmodeled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's the definition I have in mind. But it's not clear to me how your alternative implementation can be written down just in terms of predicates that are public in AliasedSSA.qll and SimpleSSA.qll. (I cheated and added a few lines to SimpleSSA.qll to make my implementation work).

or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
location.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
Copy link

Choose a reason for hiding this comment

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

I should be possible to have a Phi for a specific (non-conflated) location that happens to be part of AliasedVirtualVariable. I'm not sure if we have this specific test case, but in ssa.cpp, function MergeMustExactlyWithMustTotallyOverlap shows how this works when the location in question does not escape. You get two Phi instructions, one for the entire virtual variable, and one for the specific location within that virtual variable. See the QLDoc for the PhiInsertion module in SSAConstruction.qll for a bit more detail on the how and why.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What would a test case look like?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps this issue has to do with the test failures.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've written a test case that exhibits the problem you describe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've just pushed a commit to demonstrate the problem, followed by a commit to fix it.

* as originating on the `AliasedDefinitionInstruction` at the entry of the
* function.
*/
final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) }
Copy link

Choose a reason for hiding this comment

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

I don't think there will be much use of isResultModeled. In fact, I believe that your usage is the first outside of the Instruction class itself.

I like having unmodeled results and operands print out as mu instead of m. I do think that isResultConflated is worth displaying in IR dumps as well, though. I'm not sure what punctuation to use for that, but Emoji open up a world of possibilities:
# 134| m134_4🔀(unknown) = Chi : total:m134_2, partial:m134_3

@jbj
Copy link
Contributor Author

jbj commented Mar 20, 2020

There are test failures in the sound IR. I hadn't found these tests because I apparently grepped for the wrong thing. I'll investigate.

@jbj jbj added the WIP This is a work-in-progress, do not merge yet! label Mar 23, 2020
not use instanceof EntireAllocationMemoryLocation and
result instanceof MustTotallyOverlap
if def.getAllocation() = use.getAllocation()
Copy link

Choose a reason for hiding this comment

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

Yes, this looks right.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The DIL LGTM, and so do the tuple counts on Wireshark.

@jbj jbj removed the WIP This is a work-in-progress, do not merge yet! label Mar 24, 2020
jbj added 3 commits March 24, 2020 16:46
I had included `InitializeNonLocal` in the recursion because it made
everything look better in the presence of a bug that's since been fixed.
Taking it out means the sanity test is again aligned with the old
`isChiForAllAliasedMemory`.
…memory

Conflicts:
	cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll
	cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll
	cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll
	cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected
	cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected
	cpp/ql/test/library-tests/ir/ir/raw_sanity.expected
	cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected
	cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected
	cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected
	cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected
	cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected
	cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected
	cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected
	cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected
	cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected
	csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll
	csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll
	csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected
	csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected
Copy link

@dbartol dbartol left a comment

Choose a reason for hiding this comment

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

LGTM now

@dbartol dbartol merged commit 7879dde into github:master Mar 26, 2020
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