THRIFT-2026: Fix TCompactProtocol 64 bit builds
Client: cpp
Patch: Ben Craig
diff --git a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
index 62d6485..c444020 100644
--- a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
+++ b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
@@ -270,8 +270,15 @@
 
 template <class Transport_>
 uint32_t TCompactProtocolT<Transport_>::writeBinary(const std::string& str) {
-  uint32_t ssize = str.size();
-  uint32_t wsize = writeVarint32(ssize) + ssize;
+  if(str.size() > (std::numeric_limits<uint32_t>::max)())
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  uint32_t ssize = static_cast<uint32_t>(str.size());
+  uint32_t wsize = writeVarint32(ssize) ;
+  // checking ssize + wsize > uint_max, but we don't want to overflow while checking for overflows.
+  // transforming the check to ssize > uint_max - wsize
+  if(ssize > (std::numeric_limits<uint32_t>::max)() - wsize)
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  wsize += ssize;
   trans_->write((uint8_t*)str.data(), ssize);
   return wsize;
 }
@@ -768,7 +775,7 @@
  */
 template <class Transport_>
 int32_t TCompactProtocolT<Transport_>::zigzagToI32(uint32_t n) {
-  return (n >> 1) ^ -static_cast<int32_t>(n & 1);
+  return (n >> 1) ^ static_cast<uint32_t>(-static_cast<int32_t>(n & 1));
 }
 
 /**
@@ -776,7 +783,7 @@
  */
 template <class Transport_>
 int64_t TCompactProtocolT<Transport_>::zigzagToI64(uint64_t n) {
-  return (n >> 1) ^ -static_cast<int32_t>(n & 1);
+  return (n >> 1) ^ static_cast<uint64_t>(-static_cast<int64_t>(n & 1));
 }
 
 template <class Transport_>