mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Create bytes/string values of shorter than 32 bytes and adjust invalid encoding length accordingly
This commit is contained in:
parent
3c963eb00e
commit
3963d0ca02
@ -204,12 +204,20 @@ std::string ProtoConverter::addressValueAsString(unsigned _counter)
|
|||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ProtoConverter::fixedByteValueAsString(unsigned _width, unsigned _counter)
|
/// Returns a hex literal if _isHexLiteral is true, a string literal otherwise.
|
||||||
|
std::string ProtoConverter::hexValueAsString(
|
||||||
|
unsigned _width,
|
||||||
|
unsigned _counter,
|
||||||
|
bool _isHexLiteral
|
||||||
|
)
|
||||||
{
|
{
|
||||||
solAssert(
|
// If _width is zero (possible via a call from ...), then simply return an
|
||||||
(_width >= 1 && _width <= 32),
|
// empty (hex) string
|
||||||
"Proto ABIv2 Fuzzer: Fixed byte width is not between 1--32"
|
if (_width == 0)
|
||||||
);
|
return Whiskers(R"(<?addHexPrefix>hex</addHexPrefix>"")")
|
||||||
|
("addHexPrefix", _isHexLiteral)
|
||||||
|
.render();
|
||||||
|
|
||||||
// Masked value must contain twice the number of nibble "f"'s as _width
|
// Masked value must contain twice the number of nibble "f"'s as _width
|
||||||
unsigned numMaskNibbles = _width * 2;
|
unsigned numMaskNibbles = _width * 2;
|
||||||
// Start position of substring equals totalHexStringLength - numMaskNibbles
|
// Start position of substring equals totalHexStringLength - numMaskNibbles
|
||||||
@ -225,11 +233,21 @@ std::string ProtoConverter::fixedByteValueAsString(unsigned _width, unsigned _co
|
|||||||
// and replaces "0x" with "hex\"...\"" string.
|
// and replaces "0x" with "hex\"...\"" string.
|
||||||
// This is needed because solidity interprets a 20-byte 0x prefixed hex literal as an address
|
// This is needed because solidity interprets a 20-byte 0x prefixed hex literal as an address
|
||||||
// payable type.
|
// payable type.
|
||||||
return Whiskers(R"(hex"<value>")")
|
return Whiskers(R"(<?addHexPrefix>hex</addHexPrefix>"<value>")")
|
||||||
|
("addHexPrefix", _isHexLiteral)
|
||||||
("value", maskUnsignedIntToHex(_counter, numMaskNibbles).substr(startPos, numMaskNibbles))
|
("value", maskUnsignedIntToHex(_counter, numMaskNibbles).substr(startPos, numMaskNibbles))
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ProtoConverter::fixedByteValueAsString(unsigned _width, unsigned _counter)
|
||||||
|
{
|
||||||
|
solAssert(
|
||||||
|
(_width >= 1 && _width <= 32),
|
||||||
|
"Proto ABIv2 Fuzzer: Fixed byte width is not between 1--32"
|
||||||
|
);
|
||||||
|
return hexValueAsString(_width, _counter, /*isHexLiteral=*/true);
|
||||||
|
}
|
||||||
|
|
||||||
std::string ProtoConverter::integerValueAsString(bool _sign, unsigned _width, unsigned _counter)
|
std::string ProtoConverter::integerValueAsString(bool _sign, unsigned _width, unsigned _counter)
|
||||||
{
|
{
|
||||||
if (_sign)
|
if (_sign)
|
||||||
@ -314,10 +332,14 @@ void ProtoConverter::visit(ValueType const& _x)
|
|||||||
|
|
||||||
void ProtoConverter::visit(DynamicByteArrayType const& _x)
|
void ProtoConverter::visit(DynamicByteArrayType const& _x)
|
||||||
{
|
{
|
||||||
|
bool isBytes = _x.type() == DynamicByteArrayType::BYTES;
|
||||||
visitType(
|
visitType(
|
||||||
(_x.type() == DynamicByteArrayType::BYTES) ? DataType::BYTES : DataType::STRING,
|
isBytes ? DataType::BYTES : DataType::STRING,
|
||||||
bytesArrayTypeAsString(_x),
|
bytesArrayTypeAsString(_x),
|
||||||
bytesArrayValueAsString(getNextCounter())
|
bytesArrayValueAsString(
|
||||||
|
getNextCounter(),
|
||||||
|
isBytes
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +389,10 @@ std::string ProtoConverter::getValueByBaseType(ArrayType const& _x)
|
|||||||
case ArrayType::kBoolty:
|
case ArrayType::kBoolty:
|
||||||
return boolValueAsString(getNextCounter());
|
return boolValueAsString(getNextCounter());
|
||||||
case ArrayType::kDynbytesty:
|
case ArrayType::kDynbytesty:
|
||||||
return bytesArrayValueAsString(getNextCounter());
|
return bytesArrayValueAsString(
|
||||||
|
getNextCounter(),
|
||||||
|
_x.dynbytesty().type() == DynamicByteArrayType::BYTES
|
||||||
|
);
|
||||||
// TODO: Implement structs.
|
// TODO: Implement structs.
|
||||||
case ArrayType::kStty:
|
case ArrayType::kStty:
|
||||||
case ArrayType::BASE_TYPE_ONEOF_NOT_SET:
|
case ArrayType::BASE_TYPE_ONEOF_NOT_SET:
|
||||||
@ -695,6 +720,7 @@ void ProtoConverter::visit(TestFunction const& _x)
|
|||||||
if (returnVal != 0)
|
if (returnVal != 0)
|
||||||
return uint(200000) + returnVal;
|
return uint(200000) + returnVal;
|
||||||
|
|
||||||
|
<?atLeastOneVar>
|
||||||
bytes memory argumentEncoding = abi.encode(<parameter_names>);
|
bytes memory argumentEncoding = abi.encode(<parameter_names>);
|
||||||
|
|
||||||
returnVal = checkEncodedCall(this.coder_public.selector, argumentEncoding, <invalidLengthFuzz>);
|
returnVal = checkEncodedCall(this.coder_public.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||||
@ -704,11 +730,13 @@ void ProtoConverter::visit(TestFunction const& _x)
|
|||||||
returnVal = checkEncodedCall(this.coder_external.selector, argumentEncoding, <invalidLengthFuzz>);
|
returnVal = checkEncodedCall(this.coder_external.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||||
if (returnVal != 0)
|
if (returnVal != 0)
|
||||||
return uint(200000) + returnVal;
|
return uint(200000) + returnVal;
|
||||||
|
</atLeastOneVar>
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("parameter_names", dev::suffixedVariableNameList(s_varNamePrefix, 0, m_varCounter))
|
("parameter_names", dev::suffixedVariableNameList(s_varNamePrefix, 0, m_varCounter))
|
||||||
("invalidLengthFuzz", std::to_string(_x.invalid_encoding_length()))
|
("invalidLengthFuzz", std::to_string(_x.invalid_encoding_length()))
|
||||||
|
("atLeastOneVar", m_varCounter > 0)
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,8 +758,12 @@ void ProtoConverter::writeHelperFunctions()
|
|||||||
internal pure returns (bytes memory, bytes memory)
|
internal pure returns (bytes memory, bytes memory)
|
||||||
{
|
{
|
||||||
bytes memory validEncoding = new bytes(4 + argumentEncoding.length);
|
bytes memory validEncoding = new bytes(4 + argumentEncoding.length);
|
||||||
// Ensure that invalidEncoding crops at least one and at most all bytes from correct encoding.
|
// Ensure that invalidEncoding crops at least 32 bytes (padding length
|
||||||
uint invalidLength = invalidLengthFuzz % argumentEncoding.length;
|
// is at most 31 bytes) since shorter bytes/string values can lead to
|
||||||
|
// successful decoding when fewer than 32 bytes have been cropped in
|
||||||
|
// the worst case. In other words,
|
||||||
|
// 0 <= invalidLength <= argumentEncoding.length - 32
|
||||||
|
uint invalidLength = invalidLengthFuzz % (argumentEncoding.length - 31);
|
||||||
bytes memory invalidEncoding = new bytes(4 + invalidLength);
|
bytes memory invalidEncoding = new bytes(4 + invalidLength);
|
||||||
for (uint i = 0; i < 4; i++)
|
for (uint i = 0; i < 4; i++)
|
||||||
validEncoding[i] = invalidEncoding[i] = funcSelector[i];
|
validEncoding[i] = invalidEncoding[i] = funcSelector[i];
|
||||||
|
@ -268,13 +268,6 @@ private:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// String and bytes literals are derived by hashing a monotonically increasing
|
|
||||||
// counter and enclosing the said hash inside double quotes.
|
|
||||||
std::string bytesArrayValueAsString(unsigned _counter)
|
|
||||||
{
|
|
||||||
return "\"" + toHex(hashUnsignedInt(_counter), HexPrefix::DontAdd) + "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getQualifier(DataType _dataType)
|
std::string getQualifier(DataType _dataType)
|
||||||
{
|
{
|
||||||
return ((isValueType(_dataType) || m_isStateVar) ? "" : "memory");
|
return ((isValueType(_dataType) || m_isStateVar) ? "" : "memory");
|
||||||
@ -288,6 +281,11 @@ private:
|
|||||||
static std::string integerValueAsString(bool _sign, unsigned _width, unsigned _counter);
|
static std::string integerValueAsString(bool _sign, unsigned _width, unsigned _counter);
|
||||||
static std::string addressValueAsString(unsigned _counter);
|
static std::string addressValueAsString(unsigned _counter);
|
||||||
static std::string fixedByteValueAsString(unsigned _width, unsigned _counter);
|
static std::string fixedByteValueAsString(unsigned _width, unsigned _counter);
|
||||||
|
static std::string hexValueAsString(
|
||||||
|
unsigned _width,
|
||||||
|
unsigned _counter,
|
||||||
|
bool _isHexLiteral
|
||||||
|
);
|
||||||
static std::vector<std::pair<bool, unsigned>> arrayDimensionsAsPairVector(ArrayType const& _x);
|
static std::vector<std::pair<bool, unsigned>> arrayDimensionsAsPairVector(ArrayType const& _x);
|
||||||
static std::string arrayDimInfoAsString(ArrayDimensionInfo const& _x);
|
static std::string arrayDimInfoAsString(ArrayDimensionInfo const& _x);
|
||||||
static void arrayDimensionsAsStringVector(
|
static void arrayDimensionsAsStringVector(
|
||||||
@ -389,6 +387,19 @@ private:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String and bytes literals are derived by hashing a monotonically increasing
|
||||||
|
// counter and enclosing the (potentially cropped) hash inside double quotes.
|
||||||
|
// Cropping is achieved by masking out higher order bits.
|
||||||
|
// TODO: Test invalid encoding of bytes/string arguments that hold values of over 32 bytes.
|
||||||
|
// See https://github.com/ethereum/solidity/issues/7180
|
||||||
|
static std::string bytesArrayValueAsString(unsigned _counter, bool _isHexLiteral)
|
||||||
|
{
|
||||||
|
// We use _counter to not only create a value but to crop it
|
||||||
|
// to a length (l) such that 0 <= l <= 32 (hence the use of 33 as
|
||||||
|
// the modulo constant)
|
||||||
|
return hexValueAsString(_counter % 33, _counter, _isHexLiteral);
|
||||||
|
}
|
||||||
|
|
||||||
/// Contains the test program
|
/// Contains the test program
|
||||||
std::ostringstream m_output;
|
std::ostringstream m_output;
|
||||||
/// Temporary storage for state variable definitions
|
/// Temporary storage for state variable definitions
|
||||||
|
Loading…
Reference in New Issue
Block a user