diff --git a/c++/src/capnp/layout.c++ b/c++/src/capnp/layout.c++
index 07606ef4d9ed00cd405425df51a02e3bbcb12d13..ab41c38d767a2e91b356ffbef4e9c9e216300ad6 100644
--- a/c++/src/capnp/layout.c++
+++ b/c++/src/capnp/layout.c++
@@ -1812,13 +1812,14 @@ struct WireHelpers {
         // List of data.
         ref->listRef.set(value.elementSize, value.elementCount);
 
-        auto wholeByteSize = value.elementCount * value.step / BITS_PER_BYTE;
+        auto wholeByteSize = upgradeBound<uint64_t>(value.elementCount) * value.step / BITS_PER_BYTE;
         copyMemory(reinterpret_cast<byte*>(ptr), value.ptr, wholeByteSize);
-        auto leftoverBits = value.elementCount * value.step % BITS_PER_BYTE;
-        if (leftoverBits > 0) {
+        auto leftoverBits =
+          (upgradeBound<uint64_t>(value.elementCount) * value.step) % (BYTES * BITS_PER_BYTE);
+        if (leftoverBits > ZERO * BITS) {
           // We need to copy a partial byte.
-          uint8_t mask = (1 << leftoverBits) - 1;
-          (reinterpret_cast<byte*>(ptr))[wholeByteSize] = mask & value.ptr[wholeByteSize];
+          uint8_t mask = (1 << leftoverBits / BITS) - 1;
+          *((reinterpret_cast<byte*>(ptr)) + wholeByteSize) = mask & *(value.ptr + wholeByteSize);
         }
       }
 
@@ -3162,9 +3163,10 @@ bool ListReader::isCanonical(const word **readHead, const WirePointer *ref) {
       auto byteReadHead = reinterpret_cast<const uint8_t*>(*readHead) + truncatedByteSize;
       auto readHeadEnd = *readHead + WireHelpers::roundBitsUpToWords(bitSize);
 
-      auto leftoverBits = bitSize % 8;
-      if (leftoverBits > 0) {
-        uint8_t mask = ~((1 << leftoverBits) - 1);
+      auto leftoverBits = bitSize % (BYTES * BITS_PER_BYTE);
+      if (leftoverBits > ZERO * BITS) {
+        auto mask = ~((1 << (leftoverBits / BITS)) - 1);
+
         if (mask & *byteReadHead) {
           return false;
         }