Skip to content

Conversation

@chriseth
Copy link
Contributor

Fixes #3867

It seems like the proper thing is done for integers, but not for bytesXX types.

@chriseth chriseth requested a review from axic April 11, 2018 22:39
@chriseth
Copy link
Contributor Author

@chriseth
Copy link
Contributor Author

Ok, I think I can see why this is still fine in most cases: Whenever we store in storage, we chop additional bits, so storage is safe. Whenever we store in memory, we do an additional cleanup, and for that additional cleanup, we either widen (implicit conversion) or we do not change the size at all. In both cases, the typeOnStack is the shorter one, so we do proper cleanup.

The only case where this can be problematic that I can think of is:

contract test {
    function f() public pure returns (bytes32 r) {
        bytes32 x = bytes32(-1);
        bytes8 a = bytes8(x);
        assembly { r := a }
    }
}

@axic
Copy link
Contributor

axic commented Apr 11, 2018

Doesn't the ABI encoder does cleaning on its own?

A better test would be:

function f(bytes4 in) returns (bytes2 out) {
  out = in;
  assembly {
    if eq(in, out) { invalid() }
  }
}

m_context << ((u256(1) << (256 - typeOnStack.numBytes() * 8)) - 1);
m_context << Instruction::NOT << Instruction::AND;
}
int bytes = min(typeOnStack.numBytes(), targetType.numBytes());
Copy link
Contributor

Choose a reason for hiding this comment

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

unsigned?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

numBytes() returns int.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, what case can numBytes be negative? Is that another oversight?

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems to be an oversight since there's an assert forcing it to be unsigned: https://github.com/ethereum/solidity/blob/develop/libsolidity/ast/Types.cpp#L1146

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, this is a very old line in the code. I guess the idea was that it is easier to subtract bytes or something.

Copy link
Contributor

@axic axic left a comment

Choose a reason for hiding this comment

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

Need to be rebased and remove the extra masking in abi.encode.

@axic axic force-pushed the bytescleanup branch 2 times, most recently from f3fe04f to 161ff5e Compare April 13, 2018 01:15
@chriseth
Copy link
Contributor Author

Finished.

@chriseth
Copy link
Contributor Author

Will add documentation to inline assembly that states when accessing local variables, short types are not guaranteed to have clean higher order bits.

@chriseth
Copy link
Contributor Author

Updated.

Copy link
Contributor

@erak erak left a comment

Choose a reason for hiding this comment

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

Looks good to me.

@chriseth chriseth merged commit 3d04d83 into develop Apr 16, 2018
@axic axic deleted the bytescleanup branch April 17, 2018 10:23
To be safe, always clear the data properly before you use it
in a context where this is important:
``uint32 x = f(); assembly { x := and(x, 0xffffffff) /* now use x */ }``
To clean signed types, you can use the ``signextend`` opcode.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should have given an example.

bytes4 x = 0xffffffff;
bytes2 y = bytes2(x);
assembly { r := y }
// At this point, r and y both store four bytes, but
Copy link
Contributor

Choose a reason for hiding this comment

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

I actually wonder why shouldn't we properly apply the cleanup before the assembly block?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can actually check how the optimizer copes with cleanup done all the time.

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.

4 participants