From 4c1d39b7a2bc9e58436da0bf85edf5cd74d5a882 Mon Sep 17 00:00:00 2001
From: chriseth <chris@ethereum.org>
Date: Thu, 12 Apr 2018 00:39:20 +0200
Subject: Properly force-clean for shortening bytesXX conversions.

---
 Changelog.md                          |  1 +
 libsolidity/codegen/CompilerUtils.cpp | 19 +++++++++----------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/Changelog.md b/Changelog.md
index 91048cd5..0d436b6b 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -30,6 +30,7 @@ Bugfixes:
  * Code Generator: Bugfix in modifier lookup in libraries.
  * Code Generator: Implement packed encoding of external function types.
  * Code Generator: Treat empty base constructor argument list as not provided.
+ * Code Generator: Properly force-clean bytesXX types for shortening conversions.
  * Commandline interface: Fix error messages for imported files that do not exist.
  * Commandline interface: Support ``--evm-version constantinople`` properly.
  * DocString Parser: Fix error message for empty descriptions.
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index b4550153..4af7d905 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -684,19 +684,17 @@ void CompilerUtils::convertType(
 			// clear for conversion to longer bytes
 			solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
 			FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
-			if (targetType.numBytes() > typeOnStack.numBytes() || _cleanupNeeded)
+			if (typeOnStack.numBytes() == 0 || targetType.numBytes() == 0)
+				m_context << Instruction::POP << u256(0);
+			else if (targetType.numBytes() > typeOnStack.numBytes() || _cleanupNeeded)
 			{
-				if (typeOnStack.numBytes() == 0)
-					m_context << Instruction::POP << u256(0);
-				else
-				{
-					m_context << ((u256(1) << (256 - typeOnStack.numBytes() * 8)) - 1);
-					m_context << Instruction::NOT << Instruction::AND;
-				}
+				int bytes = min(typeOnStack.numBytes(), targetType.numBytes());
+				m_context << ((u256(1) << (256 - bytes * 8)) - 1);
+				m_context << Instruction::NOT << Instruction::AND;
 			}
 		}
-	}
 		break;
+	}
 	case Type::Category::Enum:
 		solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, "");
 		if (enumOverflowCheckPending)
@@ -798,8 +796,9 @@ void CompilerUtils::convertType(
 		bytesConstRef data(value);
 		if (targetTypeCategory == Type::Category::FixedBytes)
 		{
+			int const numBytes = dynamic_cast<FixedBytesType const&>(_targetType).numBytes();
 			solAssert(data.size() <= 32, "");
-			m_context << h256::Arith(h256(data, h256::AlignLeft));
+			m_context << (h256::Arith(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes))));
 		}
 		else if (targetTypeCategory == Type::Category::Array)
 		{
-- 
cgit v1.2.3


From 0201492bbfb18ecc73f34d10e76dc0ee8395de73 Mon Sep 17 00:00:00 2001
From: Alex Beregszaszi <alex@rtfs.hu>
Date: Fri, 13 Apr 2018 02:14:18 +0100
Subject: Remove redundant cleanup for abi.encode.

---
 libsolidity/codegen/ExpressionCompiler.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index ed5af42e..3cf46a9d 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1023,7 +1023,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
 					solAssert(function.kind() == FunctionType::Kind::ABIEncodeWithSelector, "");
 				}
 
-				// Cleanup actually does not clean on shrinking the type.
 				utils().convertType(*dataOnStack, FixedBytesType(4), true);
 
 				// stack: <memory pointer> <selector>
@@ -1034,7 +1033,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
 					let data_start := add(mem_ptr, 0x20)
 					let data := mload(data_start)
 					let mask := )" + mask + R"(
-					mstore(data_start, or(and(data, mask), and(selector, not(mask))))
+					mstore(data_start, or(and(data, mask), selector))
 				})", {"mem_ptr", "selector"});
 				m_context << Instruction::POP;
 			}
-- 
cgit v1.2.3


From bf57500e250c0ebaed4b608626245dde4b423ba1 Mon Sep 17 00:00:00 2001
From: chriseth <chris@ethereum.org>
Date: Fri, 13 Apr 2018 17:34:35 +0200
Subject: Tests for bytes cleanup.

---
 test/libsolidity/SolidityEndToEndTest.cpp | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index cbeca215..e1727ee0 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -8807,6 +8807,24 @@ BOOST_AUTO_TEST_CASE(cleanup_bytes_types)
 	ABI_CHECK(callContractFunction("f(bytes2,uint16)", string("abc"), u256(0x040102)), encodeArgs(0));
 }
 
+BOOST_AUTO_TEST_CASE(cleanup_bytes_types_shortening)
+{
+	char const* sourceCode = R"(
+		contract C {
+			function f() pure returns (bytes32 r) {
+				bytes4 x = 0xffffffff;
+				bytes2 y = bytes2(x);
+				assembly { r := y }
+				// At this point, r and y both store four bytes, but
+				// y is properly cleaned before the equality check
+				require(y == bytes2(0xffff));
+			}
+		}
+	)";
+	compileAndRun(sourceCode, 0, "C");
+	ABI_CHECK(callContractFunction("f()"), encodeArgs("\xff\xff\xff\xff"));
+}
+
 BOOST_AUTO_TEST_CASE(skip_dynamic_types)
 {
 	// The EVM cannot provide access to dynamically-sized return values, so we have to skip them.
@@ -11322,6 +11340,10 @@ BOOST_AUTO_TEST_CASE(abi_encode)
 				y[0] = "e";
 				require(y[0] == "e");
 			}
+			function f4() returns (bytes) {
+				bytes4 x = "abcd";
+				return abi.encode(bytes2(x));
+			}
 		}
 	)";
 	compileAndRun(sourceCode, 0, "C");
@@ -11329,6 +11351,7 @@ BOOST_AUTO_TEST_CASE(abi_encode)
 	ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 0x40, 1, 2));
 	ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc"));
 	ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc"));
+	ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 0x20, "ab"));
 }
 
 BOOST_AUTO_TEST_CASE(abi_encode_v2)
-- 
cgit v1.2.3


From a9c16b8c3976dbd2c386586cdf143150a4266ac0 Mon Sep 17 00:00:00 2001
From: chriseth <chris@ethereum.org>
Date: Mon, 16 Apr 2018 12:46:48 +0200
Subject: Add documentation.

---
 docs/assembly.rst | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/docs/assembly.rst b/docs/assembly.rst
index 705cd1b8..978e71e3 100644
--- a/docs/assembly.rst
+++ b/docs/assembly.rst
@@ -405,6 +405,16 @@ changes during the call, and thus references to local variables will be wrong.
         }
     }
 
+.. note::
+    If you access variables of a type that spans less than 256 bits
+    (for example ``uint64``, ``address``, ``bytes16`` or ``byte``),
+    you cannot make any assumptions about bits not part of the
+    encoding of the type. Especially, do not assume them to be zero.
+    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.
+
 Labels
 ------
 
-- 
cgit v1.2.3