mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #1351 from ethereum/truncate_bit
Truncate a boolean from calldata into one bit
This commit is contained in:
commit
84443eb560
@ -7,6 +7,7 @@ Features:
|
||||
Bugfixes:
|
||||
* Code generator: throw if calling the identity precompile failed during memory (array) copying.
|
||||
* Type checker: string literals that are not valid UTF-8 cannot be converted to string type
|
||||
* Code generator: any non-zero value given as a boolean argument is now converted into 1.
|
||||
|
||||
### 0.4.6 (2016-11-22)
|
||||
|
||||
|
@ -56,6 +56,8 @@ So for the following contract snippet::
|
||||
|
||||
The position of ``data[4][9].b`` is at ``keccak256(uint256(9) . keccak256(uint256(4) . uint256(1))) + 1``.
|
||||
|
||||
.. index: memory layout
|
||||
|
||||
****************
|
||||
Layout in Memory
|
||||
****************
|
||||
@ -72,7 +74,8 @@ Solidity always places new objects at the free memory pointer and memory is neve
|
||||
.. warning::
|
||||
There are some operations in Solidity that need a temporary memory area larger than 64 bytes and therefore will not fit into the scratch space. They will be placed where the free memory points to, but given their short lifecycle, the pointer is not updated. The memory may or may not be zeroed out. Because of this, one shouldn't expect the free memory to be zeroed out.
|
||||
|
||||
.. index: memory layout
|
||||
|
||||
.. index: calldata layout
|
||||
|
||||
*******************
|
||||
Layout of Call Data
|
||||
@ -85,6 +88,56 @@ specification
|
||||
ABI specification requires arguments to be padded to multiples of 32
|
||||
bytes. The internal function calls use a different convention.
|
||||
|
||||
|
||||
.. index: variable cleanup
|
||||
|
||||
*********************************
|
||||
Internals - Cleaning Up Variables
|
||||
*********************************
|
||||
|
||||
When a value is shorter than 256-bit, in some cases the remaining bits
|
||||
must be cleaned.
|
||||
The Solidity compiler is designed to clean such remaining bits before any operations
|
||||
that might be adversely affected by the potential garbage in the remaining bits.
|
||||
For example, before writing a value to the memory, the remaining bits need
|
||||
to be cleared because the memory contents can be used for computing
|
||||
hashes or sent as the data of a message call. Similarly, before
|
||||
storing a value in the storage, the remaining bits need to be cleaned
|
||||
because otherwise the garbled value can be observed.
|
||||
|
||||
On the other hand, we do not clean the bits if the immediately
|
||||
following operation is not affected. For instance, since any non-zero
|
||||
value is considered ``true`` by ``JUMPI`` instruction, we do not clean
|
||||
the boolean values before they are used as the condition for
|
||||
``JUMPI``.
|
||||
|
||||
In addition to the design principle above, the Solidity compiler
|
||||
cleans input data when it is loaded onto the stack.
|
||||
|
||||
Different types have different rules for cleaning up invalid values:
|
||||
|
||||
+---------------+---------------+-------------------+
|
||||
|Type |Valid Values |Invalid Values Mean|
|
||||
+===============+===============+===================+
|
||||
|enum of n |0 until n - 1 |exception |
|
||||
|members | | |
|
||||
+---------------+---------------+-------------------+
|
||||
|bool |0 or 1 |1 |
|
||||
+---------------+---------------+-------------------+
|
||||
|signed integers|sign-extended |currently silently |
|
||||
| |word |wraps; in the |
|
||||
| | |future exceptions |
|
||||
| | |will be thrown |
|
||||
| | | |
|
||||
| | | |
|
||||
+---------------+---------------+-------------------+
|
||||
|unsigned |higher bits |currently silently |
|
||||
|integers |zeroed |wraps; in the |
|
||||
| | |future exceptions |
|
||||
| | |will be thrown |
|
||||
+---------------+---------------+-------------------+
|
||||
|
||||
|
||||
*****************
|
||||
Esoteric Features
|
||||
*****************
|
||||
|
@ -926,6 +926,8 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
|
||||
if (leftAligned)
|
||||
m_context << shiftFactor << Instruction::MUL;
|
||||
}
|
||||
if (_fromCalldata)
|
||||
convertType(_type, _type, true);
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
@ -940,7 +942,7 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
|
||||
m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << Instruction::AND;
|
||||
}
|
||||
|
||||
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
|
||||
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries)
|
||||
{
|
||||
unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries);
|
||||
bool leftAligned = _type.category() == Type::Category::FixedBytes;
|
||||
@ -949,6 +951,7 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBou
|
||||
else
|
||||
{
|
||||
solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested.");
|
||||
convertType(_type, _type, true);
|
||||
if (numBytes != 32 && !leftAligned && !_padToWordBoundaries)
|
||||
// shift the value accordingly before storing
|
||||
m_context << (u256(1) << ((32 - numBytes) * 8)) << Instruction::MUL;
|
||||
|
@ -185,7 +185,7 @@ private:
|
||||
void cleanHigherOrderBits(IntegerType const& _typeOnStack);
|
||||
|
||||
/// Prepares the given type for storing in memory by shifting it if necessary.
|
||||
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
|
||||
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries);
|
||||
/// Loads type from memory assuming memory offset is on stack top.
|
||||
unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries);
|
||||
|
||||
|
@ -223,7 +223,6 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
{
|
||||
solAssert(m_dataType->storageBytes() <= 32, "Invalid storage bytes size.");
|
||||
solAssert(m_dataType->storageBytes() > 0, "Invalid storage bytes size.");
|
||||
|
||||
if (m_dataType->storageBytes() == 32)
|
||||
{
|
||||
solAssert(m_dataType->sizeOnStack() == 1, "Invalid stack size.");
|
||||
|
@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(location_test)
|
||||
shared_ptr<string const> n = make_shared<string>("");
|
||||
AssemblyItems items = compileContract(sourceCode);
|
||||
vector<SourceLocation> locations =
|
||||
vector<SourceLocation>(16, SourceLocation(2, 75, n)) +
|
||||
vector<SourceLocation>(18, SourceLocation(2, 75, n)) +
|
||||
vector<SourceLocation>(27, SourceLocation(20, 72, n)) +
|
||||
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
|
||||
vector<SourceLocation>(2, SourceLocation(58, 67, n)) +
|
||||
|
@ -4591,6 +4591,34 @@ BOOST_AUTO_TEST_CASE(super_overload)
|
||||
BOOST_CHECK(callContractFunction("h()") == encodeArgs(2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(bool_conversion)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
function f(bool _b) returns(uint) {
|
||||
if (_b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
function g(bool _in) returns (bool _out) {
|
||||
_out = _in;
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
BOOST_CHECK(callContractFunction("f(bool)", 0) == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("f(bool)", 1) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("f(bool)", 2) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("f(bool)", 3) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("f(bool)", 255) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("g(bool)", 0) == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("g(bool)", 1) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("g(bool)", 2) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("g(bool)", 3) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("g(bool)", 255) == encodeArgs(1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(packed_storage_signed)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
|
Loading…
Reference in New Issue
Block a user