Skip to content

Commit beabc51

Browse files
returnSize assigned according to truth value of returnInfo.dynamicReturnSize
1 parent ebefb5d commit beabc51

File tree

40 files changed

+261
-116
lines changed

40 files changed

+261
-116
lines changed

libsolidity/codegen/ReturnInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,6 @@ ReturnInfo::ReturnInfo(EVMVersion const& _evmVersion, FunctionType const& _funct
5454
estimatedReturnSize += retType->decodingType()->calldataEncodedSize();
5555
}
5656
}
57+
if (dynamicReturnSize)
58+
solAssert(estimatedReturnSize == 0);
5759
}

libsolidity/codegen/ir/IRGeneratorForStatements.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,6 +2505,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
25052505
appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
25062506
}
25072507

2508+
// NOTE: When the expected size of returndata is static, we pass that in to the call opcode and it gets copied automatically.
2509+
// When it's dynamic, we get zero from estimatedReturnSize() instead and then we need an explicit returndatacopy().
25082510
Whiskers templ(R"(
25092511
<?checkExtcodesize>
25102512
if iszero(extcodesize(<address>)) { <revertNoCode>() }
@@ -2514,22 +2516,29 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
25142516
mstore(<pos>, <shl28>(<funSel>))
25152517
let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>)
25162518
2517-
let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <reservedReturnSize>)
2519+
let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <staticReturndataSize>)
25182520
<?noTryCall>
25192521
if iszero(<success>) { <forwardingRevert>() }
25202522
</noTryCall>
25212523
<?+retVars> let <retVars> </+retVars>
25222524
if <success> {
2523-
<?dynamicReturnSize>
2524-
// copy dynamic return data out
2525-
returndatacopy(<pos>, 0, returndatasize())
2526-
</dynamicReturnSize>
2525+
<?isReturndataSizeDynamic>
2526+
let <returnDataSizeVar> := returndatasize()
2527+
returndatacopy(<pos>, 0, <returnDataSizeVar>)
2528+
<!isReturndataSizeDynamic>
2529+
let <returnDataSizeVar> := <staticReturndataSize>
2530+
<?supportsReturnData>
2531+
if gt(<returnDataSizeVar>, returndatasize()) {
2532+
<returnDataSizeVar> := returndatasize()
2533+
}
2534+
</supportsReturnData>
2535+
</isReturndataSizeDynamic>
25272536
25282537
// update freeMemoryPointer according to dynamic return size
2529-
<finalizeAllocation>(<pos>, <returnSize>)
2538+
<finalizeAllocation>(<pos>, <returnDataSizeVar>)
25302539
25312540
// decode return parameters from external try-call into retVars
2532-
<?+retVars> <retVars> := </+retVars> <abiDecode>(<pos>, add(<pos>, <returnSize>))
2541+
<?+retVars> <retVars> := </+retVars> <abiDecode>(<pos>, add(<pos>, <returnDataSizeVar>))
25332542
}
25342543
)");
25352544
templ("revertNoCode", m_utils.revertReasonIfDebugFunction("Target contract does not contain code"));
@@ -2558,21 +2567,18 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
25582567
templ("funSel", IRVariable(_functionCall.expression()).part("functionSelector").name());
25592568
templ("address", IRVariable(_functionCall.expression()).part("address").name());
25602569

2561-
// Always use the actual return length, and not our calculated expected length, if returndatacopy is supported.
2562-
// This ensures it can catch badly formatted input from external calls.
2563-
if (m_context.evmVersion().supportsReturndata())
2564-
templ("returnSize", "returndatasize()");
2565-
else
2566-
templ("returnSize", to_string(returnInfo.estimatedReturnSize));
2567-
2568-
templ("reservedReturnSize", returnInfo.dynamicReturnSize ? "0" : to_string(returnInfo.estimatedReturnSize));
2570+
if (returnInfo.dynamicReturnSize)
2571+
solAssert(m_context.evmVersion().supportsReturndata());
2572+
templ("returnDataSizeVar", m_context.newYulVariable());
2573+
templ("staticReturndataSize", to_string(returnInfo.estimatedReturnSize));
2574+
templ("supportsReturnData", m_context.evmVersion().supportsReturndata());
25692575

25702576
string const retVars = IRVariable(_functionCall).commaSeparatedList();
25712577
templ("retVars", retVars);
25722578
solAssert(retVars.empty() == returnInfo.returnTypes.empty());
25732579

25742580
templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true));
2575-
templ("dynamicReturnSize", returnInfo.dynamicReturnSize);
2581+
templ("isReturndataSizeDynamic", returnInfo.dynamicReturnSize);
25762582

25772583
templ("noTryCall", !_functionCall.annotation().tryCall);
25782584

0 commit comments

Comments
 (0)