-
Notifications
You must be signed in to change notification settings - Fork 523
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
Guard against overflow / wrap around of internal bit address #1106
base: master
Are you sure you want to change the base?
Conversation
I should mention that I replaced (two instances of) this code by setting the signing flag directly on the base after widening.
Just tell me if there is a good reason why the code should stay, and I'll add it back. |
When I test against the master branch, your test program only fails on the variable base expression. Is that what you expect? Although this PR appears to fix the problem, the various checks of the form |
Yes, it only fails there since there was already a bit of checking in place for constants. However if you output Verilog from the test using
There are exactly two such checks in It is unfortunate that Nitpicks aside, I guess I could just add an |
I can't speak for Steve's intentions, but bear in mind that Icarus Verilog was created before the x86_64 architecture. Also, using 64-bit values isn't a panacea. Even with your patches, this bit of code still gives the wrong result:
If we are going to fix this, we also need to look at the code that handles the LHS of assignments ( |
bb53505
to
f6f3a3a
Compare
As indicated in the comments in the test It is outside the scope of this PR to correctly handle 64 bit addresses and beyond - 64 bit numbers are only used to ensure that the part select bit accesses outside of the (current) internal 31 bit address space will return
Making the check for constant base expressions work right in all cases on Windows seems to be quite a bit of work - changing I'll see if I can come up with a solution for constant base expressions short of replacing all |
f6f3a3a
to
0c0db6e
Compare
@martinwhitaker I have now implemented checks for overflow of constant base expressions in |
0c0db6e
to
0e8fe1c
Compare
@martinwhitaker I've rewritten the code for variable base expressions to use only 32 bit numbers as well. Now the commit doesn't pretend to solve any other issue than overflow when unsigned 32 bit part select base expressions (resulting from expressions involving unsized numbers in Verilog) are converted to internal signed 32 bit addresses. I think this is now minimally intrusive, and I hope it is more to your liking. |
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.
Finally found time to review this more thoroughly. Please see comments inline.
elab_expr.cc
Outdated
@@ -5958,6 +5958,23 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, | |||
if (base_c->value().is_defined()) { | |||
long lsv = base_c->value().as_long(); | |||
long rel_base = 0; | |||
|
|||
// Check whether an unsigned base fits in a 32 bit int, | |||
// which is what will be used for addressing later on. |
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.
This seems to be unnecessary. The compiler already handles your test case for a constant base correctly. If you compile with -Wall, it will issue an appropriate warning too.
The same goes for the similar changes below.
If you disagree, please provide a test case that fails.
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 finally found the time to look at this again with a fresh pair of eyes. I have addressed the comments in your thorough review, and I have cleaned up, corrected, and commented the code to make it more understandable.
As mentioned earlier, if you run the test for constant base through -t vlog95
first, it will fail. I believe it will also fail right away on Windows (LLP64), however I can't test that.
ivtest/regress-sv.list
Outdated
@@ -980,6 +980,7 @@ br_gh840a CE,-g2012 ivltests | |||
br_gh840b CE,-g2012 ivltests | |||
br_gh979 normal,-g2012 ivltests | |||
bitsel_real_idx CE,-g2012 ivltests gold=bitsel_real_idx.gold | |||
partsel_outside normal,-g2005-sv ivltests |
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.
New tests should be added to the new python-based test framework (see https://steveicarus.github.io/iverilog/developer/regression_tests.html).
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.
OK, done.
netmisc.cc
Outdated
long offset = msb_lo ? soff + lsb : soff - lsb; | ||
|
||
/* Correct the offset if needed. */ | ||
if (!msb_lo ^ is_up) offset -= wid - 1; |
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.
This is correct, but is not easy to understand. I suggest the following:
/* Calculate the canonical offset. */
long offset = soff;
if (msb_lo) {
offset += lsb;
if (is_up)
offset -= wid - 1;
} else {
offset -= lsb;
if (!is_up)
offset -= wid - 1;
}
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.
OK, done.
netmisc.cc
Outdated
|
||
/* Calculate the space needed for the offset. */ | ||
unsigned off_wid = num_bits(offset); | ||
unsigned off_max_wid = max(off_wid, num_bits(offset + wid - 1)); |
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 don't understand the need for this extra expansion. We end up generating an expression to calculate base + offset
or offset - base
, so where does offset + wid + 1
come into it?
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.
That was due to a misunderstanding on my part. I speculated that the normalized base
had to be padded to account for addition of the topmost bit of the selected slice, which evidently is not the case.
netmisc.cc
Outdated
if ((offset < 0 || (msb_lo && off_wid <= base_wid)) && ! base->has_sign()) { | ||
unsigned signed_wid = 1 + base->expr_width(); | ||
base = pad_to_width(base, signed_wid, *base); | ||
base->cast_signed(true); |
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.
This is only safe if off_max_wid
is non-zero and the earlier pad_to_width()
has already zero-extended base
. If not, the immediately preceding pad_to_width()
will sign-extend base
. As it happens, I think your extra expansion of off_max_wid
guarantees it will never be zero, but if that is removed, you will need to restore the additional NetESelect
here to separate the cast from the padding.
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.
It turns out that the NetESelect
is necessary to generate the correct %pad/u
, otherwise cast_signed
will become part of the previous pad_to_width
, and %pad/s
will be generated.
It basically says so in the comments, I just didn't catch the meaning of it since I didn't know the code base and this somewhat counterintuitive behavior.
The required bit width for the address calculation should now be exactly determined in all cases. The normalization is also considerably simplified.
056145e
to
9b6dc2d
Compare
Internally, the maximum address space of a vector is 31 bits + a sign bit to signal invalid addresses (out of bounds or has one or more x or z bits). This commit ensures that unsigned part-select bit addresses which would otherwise overflow and wrap around within this address space are correctly handled as out of bounds.
9b6dc2d
to
ba7da9d
Compare
Internally, the maximum address space of a vector is 31 bits + a sign bit
to signal invalid addresses (out of bounds or has one or more x or z bits).
This pull request ensures that unsigned parts-select bit addresses which would
otherwise overflow and wrap around within this address space are correctly
handled as out of bounds.