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

Use returndatacopy for retrieving dynamically sized outputs. #3308

Merged
merged 6 commits into from
Mar 21, 2018

Conversation

chriseth
Copy link
Contributor

@chriseth chriseth commented Dec 12, 2017

Fixes #3270
Fixes #2964
Fixes #3273
Fixes #3516

Depends on #3569

@chriseth chriseth changed the title [WIP] Use returndatacopy for retrieving dynamically sized outputs. Use returndatacopy for retrieving dynamically sized outputs. Dec 13, 2017
@chriseth chriseth requested a review from axic December 13, 2017 16:30
@chriseth
Copy link
Contributor Author

chriseth commented Dec 13, 2017

This is ready for review.

Decisions to be taken:

  • do we want to enable this by default - some VMs might not have returndatacopy?
  • this might lead to problems when the returned data invalid data pointers in the ABI encoding (it still uses the old decoder unless the new is active). It is worse than with calldata because everything will reside in memory and we do not have zero-extension there because we need to copy from memory to memory.

else
m_context << Instruction::POP;
{
utils().fetchFreeMemoryPointer();
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 should add a size check here, too.

@AnthonyAkentiev
Copy link

Hi guys. Is it still not merged?

@chriseth
Copy link
Contributor Author

@AnthonyAkentiev someone is impatient there :)

There are still security issues to be discussed, see above.

@chriseth
Copy link
Contributor Author

The first comment above is solved (pragma target byzantium), but for the second comment, we probably do not want this to run with the old ABI decoder.

@axic
Copy link
Member

axic commented Jan 25, 2018

Perhaps we could remove the InaccessibleDynamicType in a separate pull request because it should already be covered with an assertion. (Need to verify that.)

@chriseth
Copy link
Contributor Author

Use the old decoder only on statically-sized data or on the statically-sized head of dynamically-sized data. This means returndatacopy is not used with the old decoder.

// Alter dynamic types to be non-accessible.
for (auto& param: returnParameterTypes)
if (param->isDynamicallySized())
param = make_shared<InaccessibleDynamicType>();
Copy link
Member

Choose a reason for hiding this comment

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

We could move this check into the TypeChecker around line 1500.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

... only if the pragma specifies that we are using the old encoder.

@axic
Copy link
Member

axic commented Feb 14, 2018

Should use the new evmTarget from #1117.

@chriseth chriseth force-pushed the usereturndatacopy branch 3 times, most recently from 352cf60 to 5ecc33c Compare February 21, 2018 15:10
@chriseth chriseth force-pushed the usereturndatacopy branch 2 times, most recently from d938d19 to 693858d Compare February 23, 2018 18:39
@chriseth
Copy link
Contributor Author

This is finished, but I still have to untangle the various commits.

@chriseth
Copy link
Contributor Author

Commits untangled.

@chriseth chriseth force-pushed the usereturndatacopy branch from 6f26336 to 645098d Compare March 5, 2018 11:27
@chriseth
Copy link
Contributor Author

chriseth commented Mar 5, 2018

Rebased.

@chriseth chriseth force-pushed the usereturndatacopy branch from 645098d to 22dc19d Compare March 5, 2018 11:32
@chriseth
Copy link
Contributor Author

chriseth commented Mar 5, 2018

Ready for review.

@axic
Copy link
Member

axic commented Mar 7, 2018

Ah, the problem is Github lists commits in the wrong order (by timestamp), but merge wise Move the old ABI decoder code comes before Simple size check for old ABI decoder..

@chriseth
Copy link
Contributor Author

chriseth commented Mar 7, 2018

Oh wow that is interesting. I last rebased two days ago.

// Check that the data pointer is valid and that length times
// item size is still inside the range.
Whiskers templ(R"({
if gt(ptr, 0x100000000) { revert(0, 0) }
Copy link
Member

Choose a reason for hiding this comment

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

Is this a random constant (we assume it is not possible to transfer that much due to block gas limits)?

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you want something to be changed here?


if (m_kind == Kind::External || m_kind == Kind::CallCode || m_kind == Kind::DelegateCall)
for (auto& param: returnParameterTypes)
if (param->isDynamicallySized() && !param->dataStoredIn(DataLocation::Storage))
Copy link
Member

Choose a reason for hiding this comment

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

Can an external call return a storage pointer?

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, but only via delegatecall.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I.e. only a call to a library function.


bool dynamicReturnSize = false;
for (auto const& retType: returnTypes)
if (retType->isDynamicallyEncoded())
Copy link
Member

Choose a reason for hiding this comment

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

Don't we have calldataEncodedSize and isDynamicallyEncoded on the TupleType, do we need to iterate?

Copy link
Member

@axic axic Mar 20, 2018

Choose a reason for hiding this comment

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

Apparently no, but would it make sense to do so?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tuples are not fully-fledged types in Solidity, so I'm not sure which implications this would have.

Copy link
Member

Choose a reason for hiding this comment

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

Let's postpone it. Created issue #3769.

else
m_context << Instruction::POP;
solAssert(retSize > 0, "");
m_context << (haveReturndatacopy ? eth::AssemblyItem(Instruction::RETURNDATASIZE) : u256(retSize));
Copy link
Member

Choose a reason for hiding this comment

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

Why not just move this into the two parts of the if?

Copy link
Member

Choose a reason for hiding this comment

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

I guess it is a separate step to always use returndatacopy and not allocate the memory on call.

Copy link
Member

Choose a reason for hiding this comment

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

I'll add a comment here stating:

Always use the actual return length, and not our calculated expected length, if returndatacopy is supported. This ensures it can catch badly formatted input from external calls.

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 was the idea, always use returndatacopy to detect badly formatted return data. Yes, please add the comment.

Copy link
Member

@axic axic Mar 20, 2018

Choose a reason for hiding this comment

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

Actually I think this may warrant its own changelog entry as we're changing behaviour.

Compiling for byzantium (which is the default) may result in a new contract not working with an old one, if we had a case of invalid short encoding, or if the other one isn't Solidity and doesn't encode properly.

Unlikely, but still.

@axic axic force-pushed the usereturndatacopy branch from 7c3de57 to c7860a0 Compare March 21, 2018 14:53
/// From memory if @a _fromMemory is true, otherwise from call data.
/// Calls revert if @a _revertOnOutOfBounds is true and the supplied size is shorter
/// than the static data requirements or if dynamic data pointers reach outside of the
/// area. Also has a hard cap of 0x100000000 for any given length/offset field.
Copy link
Member

Choose a reason for hiding this comment

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

@chriseth added this comment also

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