-
Notifications
You must be signed in to change notification settings - Fork 248
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
fix!: Only decrement the counter of an array if its address has not changed #7297
Conversation
@michaeljklein I tried running this on
All 4 tests in this quite failed:
I'll push the branch to see the full extent of it in AztecProtocol/aztec-packages#11763 |
This is more reason to experiment with #7287 I think. Ref counts being these implicit values passed around along with arrays has lead to footguns in the past and:
Certainly sounds like such a footgun as well. |
As a bonus, I suspect once we do fix ref counts we should see a brillig speedup as well since I'd expect a well-behaved ref count to hover around 1 much more often since it is no longer drifting off. |
Basically every test in aztec-packages fails with this assertion: https://github.com/AztecProtocol/aztec-packages/actions/runs/13164114024 |
@michaeljklein I did the experiment you suggested to detect whether the RC goes negative by moving the assertion AztecProtocol/aztec-packages@6217ca5 I'm afraid the results on In the |
dec_rc
4652543 changes how the |
Changes to number of Brillig opcodes executed
🧾 Summary (10% most significant diffs)
Full diff report 👇
|
Changes to Brillig bytecode sizes
🧾 Summary (10% most significant diffs)
Full diff report 👇
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not confident this is the correct fix or whether its applying a bandaid over a broken system, which could still be broken somewhere else after.
If it improves on what we currently have it could be good as a temporary fix but I'd like to see some test cases we currently fail with for a change like this to show that.
Blocking this PR before we have such tests but I wont "request changes" since I'm off next week to avoid keeping this blocked then once tests are added.
It's meant as a band-aid over a clear case that can cause the ref count to be decreased to zero, but it doesn't prevent the ref count from creeping up when there are no The test failure can be provoked like this:
I'll try to write a test using the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After going through the discussions on this PR and the issue, I do think this is a reasonable temporary fix. Especially as we are planning to experiment with an overhaul of our RCs. Having the original array as part of the dec_rc does look provide us some connection to the original inc_rc for which the dec_rc was intended.
I have a couple nits and clarifying questions surrounding the test you added, but otherwise I am good to merge.
chore: update docs about integer overflows (noir-lang/noir#7370) fix!: Only decrement the counter of an array if its address has not changed (noir-lang/noir#7297) fix: let LSP read `noirfmt.toml` for formatting files (noir-lang/noir#7355)
Automated pull of development from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE chore: avoid u128s in brillig memory (noir-lang/noir#7363) chore: update docs about integer overflows (noir-lang/noir#7370) fix!: Only decrement the counter of an array if its address has not changed (noir-lang/noir#7297) fix: let LSP read `noirfmt.toml` for formatting files (noir-lang/noir#7355) END_COMMIT_OVERRIDE --------- Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
* master: (42 commits) fix: give "correct" error when trying to use AsTraitPath (#7360) chore: avoid u128s in brillig memory (#7363) chore: update docs about integer overflows (#7370) fix!: Only decrement the counter of an array if its address has not changed (#7297) fix: let LSP read `noirfmt.toml` for formatting files (#7355) chore: deprecate keccak256 (#7361) feat: `FunctionDefinition::as_typed_expr` (#7358) feat(performance): Check sub operations against induction variables (#7356) chore: avoid doing all brillig integer arithmetic on u128s (#7357) feat(cli): Add `--target-dir` option (#7350) fix(ssa): Make the lookback feature opt-in (#7190) feat(performance): Use unchecked ops based upon known induction variables (#7344) chore: mark sha256 as deprecated from the stdlib (#7351) fix: incorrect secondary file in LSP errors (#7347) chore: Basic test for MSM in Noir to catch performance improvements and regressions (#7341) fix(cli): Only lock the packages selected in the workspace (#7345) chore: remove some unused types and functions in the AST (#7339) chore: remove foreign calls array from Brillig VM constructor (#7337) chore(ci): Add Vecs and vecs to cspell (#7342) chore: redo typo PR by osrm (#7238) ...
…rom-brillig * master: chore: allow opting in to displaying benchmark comments (#7399) chore: box `ExprValue` in `Value` enum (#7388) chore: pull out refactored methods from u128 branch (#7385) feat: require safety comments instead of safety doc comments (#7295) fix(ssa): Do not deduplicate division by a zero constant (#7393) chore: document traits required to be in scope (#7387) fix: field zero division in brillig (#7386) chore: box `ParserError`s in `InterpreterError` (#7373) chore: remove unnecessary dereferencing within brillig vm (#7375) fix: give "correct" error when trying to use AsTraitPath (#7360) chore: avoid u128s in brillig memory (#7363) chore: update docs about integer overflows (#7370) fix!: Only decrement the counter of an array if its address has not changed (#7297) fix: let LSP read `noirfmt.toml` for formatting files (#7355) chore: deprecate keccak256 (#7361) feat: `FunctionDefinition::as_typed_expr` (#7358) feat(performance): Check sub operations against induction variables (#7356) chore: avoid doing all brillig integer arithmetic on u128s (#7357)
Description
Problem*
Trying to reproduce an issue we observed a while ago that array ref counts can go down to 0 and then to
usize::MAX
with an underflow if there are moredec_rc
thaninc_rc
. Once that happens it is very hard to argue that subsequent ref-count values will make sense, and in particular that when the RC will equal 1 again, then it means the array is okay to be treated as mutable.I observed
usize::MAX
while debugging some of the issues while syncing aztec-packages.Summary*
Generated an extra constraint in Brillig after
DecreaseRc
that checks that the value is at least 1. I added this to find counter examples; I realise that it would increase the bytecode size to protect against something we should not be doing in the first place, so ideally this check can be removed, or made pedantic. In the end I added a--enable-brillig-debug-assertions
flag to turn this check on (it's off by default), and threaded it through the application in a newBrilligOptions
together with the flag to enable debug printing.Came up with a fix for the status quo explained in this comment, which is to only carry out the decrement of the RC if an
array_set
has not created a new array; if it did then it would have also adjusted the original RC.The fix is breaking because of the changing in the SSA format:
dec_rc
has an extra parameter now.Additional Context
There were some fixes related to RC's in AztecProtocol/aztec-packages#11294 and with those in place there is only one test in this repo which fails, which is perhaps ironically the
reference_counts
test. With the fixes to the DIE pass removed, thebrillig_rc_regression_6123
also fails with the same error.Here's what I saw investigating the
reference_counts
test failure:Looking at the SSA what stands out is the following.
In the test we have this part:
So we write 5 and 6 into the same array through two different references.
Before Mem2Reg (2nd) it appears in the SSA like so:
There is one
inc_rc
and onedec_rc
which act on thev3
array, loaded through thev4
reference.IIUC the RC being 2 means that
array_set
will create a copy, but because it stores it back intov4
, botharray_set
will write to the same reference and thus only the last will survive.What I don't fully understand is that I thought that when we make a copy, the RC of the new array is 1, so when we call
dec_rc v21
I'm not sure it's not decrementing 1 to 0.After the Mem2Reg (2nd) pass, the storing of 6 into the array turns into the creation of a new array instead:
Notice how
dec_rc v14
is now acting on a new array. If that array had a ref-count of 1 start with, then it's now 0.Documentation*
Check one:
PR Checklist*
cargo fmt
on default settings.