From 20054e95de34877e3c6779a997382686c4aa8aa6 Mon Sep 17 00:00:00 2001
From: Jessica Clarke <jrtc27@jrtc27.com>
Date: Fri, 12 Aug 2022 19:50:57 +0100
Subject: [PATCH 2/8] tclInt: Fix (U)INT2PTR/PTR2(U)INT for CHERI

This is needed to support CHERI, and thus Arm's experimental Morello
prototype, where pointers are implemented using unforgeable capabilities
that include bounds and permissions metadata to provide fine-grained
spatial and referential memory safety, as well as revocation by sweeping
memory to provide heap temporal memory safety.

ptrdiff_t and size_t are integer types that can hold (un)signed offsets
within an object, but it is not guaranteed that they can round-trip
pointers losslessly, unlike (u)intptr_t. On CHERI, the former are plain
word-sized integers, but the latter are full capabilities, allowing this
metadata to be preserved; if the metadata is not preserved, any attempt
to dereference the resulting pointer will trap. Thus, use (u)intptr_t
rather than ptrdiff_t/size_t for pointer<->integer casts.

Note that these types are defined in stdint.h (and our compat/stdint.h
has fallback definitions) so we add an include for that. tclUnixSock
also assumed that PTR2INT gave something that could be printed as a
size_t but that is not true on CHERI so cast appropriately (and use the
unsigned variant of the macro to mirror its use whilst at it).
---
 generic/tclInt.h   | 13 +++++++++----
 unix/tclUnixSock.c |  8 ++++----
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/generic/tclInt.h b/generic/tclInt.h
index b6d5b9a87..991eee476 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -66,6 +66,11 @@
 
 #include <ctype.h>
 #include <stdarg.h>
+#ifdef HAVE_STDINT_H
+#   include <stdint.h>
+#else
+#   include "../compat/stdint.h"
+#endif
 #ifdef NO_STDLIB_H
 #   include "../compat/stdlib.h"
 #else
@@ -111,16 +116,16 @@
  */
 
 #if !defined(INT2PTR)
-#   define INT2PTR(p) ((void *)(ptrdiff_t)(p))
+#   define INT2PTR(p) ((void *)(intptr_t)(p))
 #endif
 #if !defined(PTR2INT)
-#   define PTR2INT(p) ((ptrdiff_t)(p))
+#   define PTR2INT(p) ((intptr_t)(p))
 #endif
 #if !defined(UINT2PTR)
-#   define UINT2PTR(p) ((void *)(size_t)(p))
+#   define UINT2PTR(p) ((void *)(uintptr_t)(p))
 #endif
 #if !defined(PTR2UINT)
-#   define PTR2UINT(p) ((size_t)(p))
+#   define PTR2UINT(p) ((uintptr_t)(p))
 #endif
 
 #if defined(_WIN32) && defined(_MSC_VER)
diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c
index f413b5b61..9a217a4e7 100644
--- a/unix/tclUnixSock.c
+++ b/unix/tclUnixSock.c
@@ -1448,7 +1448,7 @@ Tcl_OpenTcpClient(
         return NULL;
     }
 
-    sprintf(channelName, SOCK_TEMPLATE, PTR2INT(statePtr));
+    sprintf(channelName, SOCK_TEMPLATE, (size_t)PTR2UINT(statePtr));
 
     statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
             statePtr, TCL_READABLE | TCL_WRITABLE);
@@ -1515,7 +1515,7 @@ TclpMakeTcpClientChannelMode(
     statePtr->fds.fd = PTR2INT(sock);
     statePtr->flags = 0;
 
-    sprintf(channelName, SOCK_TEMPLATE, PTR2INT(statePtr));
+    sprintf(channelName, SOCK_TEMPLATE, (size_t)PTR2UINT(statePtr));
 
     statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
 	    statePtr, mode);
@@ -1737,7 +1737,7 @@ Tcl_OpenTcpServerEx(
             memset(statePtr, 0, sizeof(TcpState));
             statePtr->acceptProc = acceptProc;
             statePtr->acceptProcData = acceptProcData;
-            sprintf(channelName, SOCK_TEMPLATE, PTR2INT(statePtr));
+            sprintf(channelName, SOCK_TEMPLATE, (size_t)PTR2UINT(statePtr));
             newfds = &statePtr->fds;
         } else {
             newfds = (TcpFdList *)Tcl_Alloc(sizeof(TcpFdList));
@@ -1829,7 +1829,7 @@ TcpAccept(
     newSockState->flags = 0;
     newSockState->fds.fd = newsock;
 
-    sprintf(channelName, SOCK_TEMPLATE, PTR2INT(newSockState));
+    sprintf(channelName, SOCK_TEMPLATE, (size_t)PTR2INT(newSockState));
     newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
 	    newSockState, TCL_READABLE | TCL_WRITABLE);
 
-- 
2.34.GIT

