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

Bug in partial evaluation: self-comparison missing #4848

Closed
johanneskra opened this issue Jul 6, 2022 · 4 comments · Fixed by #4936
Closed

Bug in partial evaluation: self-comparison missing #4848

johanneskra opened this issue Jul 6, 2022 · 4 comments · Fixed by #4936
Labels

Comments

@johanneskra
Copy link

Short description

There seems to be a bug in the partial evaluation when doing self-comparisons. Self-comparisons are missing in the result.

Steps To Reproduce

  1. Create a file named data.json with the following content:
{
  "a": "hello"
}
  1. The normal evaluation works as expected:
opa eval --input data.json --format=pretty 'input.a == input.a'
# > output: true

opa eval --format=pretty 'input.a == input.a'
# > output: undefined

As you can see, even though input.a is compared with itself, it is not guaranteed to always return true.
The evaluation returns undefined if a is not supplied.

  1. However, in the partial evaluation, this is not taken into consideration. The condition input.a == input.a is missing from the result:
opa eval --format=pretty --partial 'input.a == input.a' --unknowns input.a
# > output: "| Query 1 |  |"

Expected behavior

I would expect the condition input.a == input.a to be in the query result since it might be false/undefined.

So the expected output would be:

| Query 1 | input.a = input.a |

Additional context

I tested this with OPA v0.41.0.

@johanneskra johanneskra added the bug label Jul 6, 2022
@srenatus
Copy link
Contributor

srenatus commented Jul 6, 2022

Thanks for the report!

@srenatus
Copy link
Contributor

One could argue that the use of input.a == input.a in a policy is rather uncommon. Semantically, it's the same as saying _ = input.a, which would (I hope) not get eaten during PE. I'd using that instead an option for you, as a workaround?

That said, PE should not drop meaningful queries, that's for sure, so the bug is valid. It just strikes me as avoidable. 🤔

@srenatus
Copy link
Contributor

FWIW I suspect it's copy propagation, but there's no way to quickly try this just using opa eval

@srenatus
Copy link
Contributor

📜 Just some notes, thinking aloud

Looks like the bug is two-fold: copyprop fails to recognize the necessity to keep something for input.a == input.a, but also partially evaluating a policy,

package p
a { input.a == input.a }

eliminates it -- because when that calls copyprop, it doesn't pass input as livevar. 🔍

💡 When input.a == input.a is fed as query into PartialRun, it'll be rewritten to

__localq0__ = input.a
__localq1__ = input.a
equal(__localq0__, __localq1__)

and for that, the previous copyprop logic was sufficient.

srenatus added a commit to srenatus/opa that referenced this issue Jul 26, 2022
Before, a query of

    input.a == input.a

would not survive copypropagation.

With this change, it'll be recorded as removedEq, and subsequent processing
steps ensure that it's kept in the body.

Changing the sort order in sortBindings allows us to limit the unnecessary
variable bindings: with the previous ordering, we'd get

    __local0__1 = input; __localcp0__ = input.a

for the query `x := input; input.a == input.a`. Sorting the other way, we'll
process `__localcp0__ = input.a` first, add it to the body, and when we check
`__local0__1 = input`, we find that `input` is already contained in the body,
and is thus not needed.

Fixes open-policy-agent#4848.

Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
srenatus added a commit that referenced this issue Jul 26, 2022
Before, a query of

    input.a == input.a

would not survive copypropagation.

With this change, it'll be recorded as removedEq, and subsequent processing
steps ensure that it's kept in the body.

Changing the sort order in sortBindings allows us to limit the unnecessary
variable bindings: with the previous ordering, we'd get

    __local0__1 = input; __localcp0__ = input.a

for the query `x := input; input.a == input.a`. Sorting the other way, we'll
process `__localcp0__ = input.a` first, add it to the body, and when we check
`__local0__1 = input`, we find that `input` is already contained in the body,
and is thus not needed.

Fixes #4848.

Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
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 a pull request may close this issue.

2 participants