Skip to content

Don't allow underflow when calculating spans #35990

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

Closed

Conversation

sgrif
Copy link
Contributor

@sgrif sgrif commented Aug 25, 2016

This subtraction can take place when doing things like creating a field
access expression through the AST builder
(and in
fact, as best I can tell, that's the only place it occurs)

The assumption is that the given span starts and ends a the last byte of
the field access. However, when doing macro expansion such as custom
derive (or any other place the AST builder would manually be used), it's
quite common to use the site of expansion as the span, as there's no
other printable span to show. If that macro expansion is the first line
of a file, the compiler will panic from underflow.

Since byte positions are unsized, and performing this subtraction in a
situation for underflow pretty much universally means you want to remain
at 0, I've fixed this in the sub impl rather than the two problem cases
of the AST builder.

This subtraction can take place when doing things like creating a [field
access expression through the AST builder][builder field access] (and in
fact, as best I can tell, that's the only place it occurs)

[builder field access]: https://github.com/rust-lang/rust/blob/a5e5ea1646367b82864af3a2a508993d76b792af/src/libsyntax/ext/build.rs#L636-L645

The assumption is that the given span starts and ends a the last byte of
the field access. However, when doing macro expansion such as custom
derive (or any other place the AST builder would manually be used), it's
quite common to use the site of expansion as the span, as there's no
other printable span to show. If that macro expansion is the first line
of a file, the compiler will panic from underflow.

Since byte positions are unsized, and performing this subtraction in a
situation for underflow pretty much universally means you want to remain
at 0, I've fixed this in the sub impl rather than the two problem cases
of the AST builder.
@rust-highfive
Copy link
Contributor

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @brson (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@@ -549,7 +549,8 @@ impl Sub for BytePos {
type Output = BytePos;

fn sub(self, rhs: BytePos) -> BytePos {
BytePos((self.to_usize() - rhs.to_usize()) as u32)
let new_pos = self.to_usize().checked_sub(rhs.to_usize()).unwrap_or(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

saturating_sub?

@@ -549,7 +549,8 @@ impl Sub for BytePos {
type Output = BytePos;

fn sub(self, rhs: BytePos) -> BytePos {
BytePos((self.to_usize() - rhs.to_usize()) as u32)
let new_pos = self.to_usize().saturating_sub(rhs.to_usize());
BytePos(new_post as u32)
Copy link
Contributor

Choose a reason for hiding this comment

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

typo new_pos[t]

@arielb1
Copy link
Contributor

arielb1 commented Aug 25, 2016

The span mangling in expr_field_access/expr_tup_field_access looks pretty bogus:

    fn expr_field_access(&self, sp: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr> {
          let field_span = Span {
              lo: sp.lo - Pos::from_usize(ident.name.as_str().len()),
              hi: sp.hi,
              expn_id: sp.expn_id,
          };
          // ...
    }

It does not feel like it will create the correct span even in the "macro-free" (e.g. I would the correct span to be sp.hi - ... instead of sp.lo - ...). Also, syntax::ext::build should not be mangling spans, because that is of course totally bogus in a syntax extension context.

cc @nrc

@sgrif
Copy link
Contributor Author

sgrif commented Aug 25, 2016

I agree that it felt incorrect for that span to be modified at all, but I was unsure if there was a reason or not so this felt like the more conservative change. I would be fine with changing the offending code to use the passed span instead.

@nrc
Copy link
Member

nrc commented Aug 25, 2016

r? @nrc

@rust-highfive rust-highfive assigned nrc and unassigned brson Aug 25, 2016
@nrc
Copy link
Member

nrc commented Aug 26, 2016

So, I think @arielb1 is right on both points - the span calculation is wrong, and build shouldn't be doing this calculation at all - there is no guarantee that the ident's span is within the given span or even that it's span is valid. We should fix this and I'll file an issue.

So, I'm a bit reluctant to merge this PR - it feels like we should never hit this situation, and if we overflow then it is always because the caller screwed up, and therefore panicking is the correct response. On the other hand, that is not very defensive programming, so maybe it is better to have this than not. I'll ponder a bit.

In any case, thanks @sgrif and @arielb1 for finding this issue and digging into it.

@sgrif
Copy link
Contributor Author

sgrif commented Aug 26, 2016

If we're fine with dumping the span mangling this PR is unnecessary IMO. Happy to update to dump the span mangling instead.

@nrc
Copy link
Member

nrc commented Aug 28, 2016

@sgrif it would be great if you wanted up update the span mangling. Given that we agree that that is the way forward, I'll close this PR.

@nrc nrc closed this Aug 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants