From 2d7a6cedc5eeed32adfe4cff14cba175f8b46c2a Mon Sep 17 00:00:00 2001
From: Jessica Clarke <jrtc27@jrtc27.com>
Date: Fri, 12 Aug 2022 19:59:24 +0100
Subject: [PATCH 4/8] tclExecute: Fix for CHERI by not assuming ptrdiff_t is a
 pointer

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 is an integer type that can hold a signed offset within an
object. On CHERI, this is a word-sized integer, but pointers are
capabilities, twice the size of that. The type pointed to by catchTop
must be the same size as the actual object stack entries (Tcl_Obj *) but
catchTop is currently a ptrdiff_t * so on CHERI this does not currently
hold, giving similar behaviour as sen on 64-bit Windows with the initial
backed-out fix for bug 3274728.

Instead, use a pointer type for catchTop's pointee type. We could use
intptr_t and that would work on CHERI, but the C standard does not in
fact guarantee that (u)intptr_t are the same size as object pointers,
merely that a pointer can be cast to (u)intptr_t and back losslessly
(thus, (u)int64_t would be a conforming, if foolish, implementation of
(u)intptr_t on a system where pointers themselves are represented as
32-bit integers). To be sure the sizes agree, use Tcl_Obj * as the
pointee type for catchTop as well and (un)wrap with PTR2INT/INT2PTR as
needed; this also allows stack to be a Tcl_Obj *[1] and removes casting
in initCatchTop and initTosPtr, making it clear these types are meant to
be the same.
---
 generic/tclExecute.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index c8d2869ae..eccf0e1ee 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -111,11 +111,11 @@ size_t		tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
 typedef struct {
     ByteCode *codePtr;		/* Constant until the BC returns */
 				/* -----------------------------------------*/
-    ptrdiff_t *catchTop;	/* These fields are used on return TO this */
+    Tcl_Obj **catchTop;		/* These fields are used on return TO this */
     Tcl_Obj *auxObjList;	/* this level: they record the state when a */
     CmdFrame cmdFrame;		/* new codePtr was received for NR */
                                 /* execution. */
-    void *stack[1];		/* Start of the actual combined catch and obj
+    Tcl_Obj *stack[1];		/* Start of the actual combined catch and obj
 				 * stacks; the struct will be expanded as
 				 * necessary */
 } TEBCdata;
@@ -1878,8 +1878,8 @@ ArgumentBCEnter(
  *----------------------------------------------------------------------
  */
 #define	bcFramePtr	(&TD->cmdFrame)
-#define	initCatchTop	((ptrdiff_t *) (TD->stack-1))
-#define	initTosPtr	((Tcl_Obj **) (initCatchTop+codePtr->maxExceptDepth))
+#define	initCatchTop	(TD->stack-1)
+#define	initTosPtr	(initCatchTop+codePtr->maxExceptDepth)
 #define esPtr		(iPtr->execEnvPtr->execStackPtr)
 
 int
@@ -6411,7 +6411,7 @@ TEBCresume(
 	 * stack.
 	 */
 
-	*(++catchTop) = CURR_DEPTH;
+	*(++catchTop) = INT2PTR(CURR_DEPTH);
 	TRACE(("%u => catchTop=%d, stackTop=%d\n",
 		TclGetUInt4AtPtr(pc+1), (int) (catchTop - initCatchTop - 1),
 		(int) CURR_DEPTH));
@@ -7326,8 +7326,8 @@ TEBCresume(
 
 	while (auxObjList) {
 	    if ((catchTop != initCatchTop)
-		    && (*catchTop > (ptrdiff_t)
-			auxObjList->internalRep.twoPtrValue.ptr2)) {
+		    && (PTR2INT(*catchTop) >
+			PTR2INT(auxObjList->internalRep.twoPtrValue.ptr2))) {
 		break;
 	    }
 	    POP_TAUX_OBJ();
@@ -7402,7 +7402,7 @@ TEBCresume(
 	 */
 
     processCatch:
-	while (CURR_DEPTH > *catchTop) {
+	while (CURR_DEPTH > PTR2INT(*catchTop)) {
 	    valuePtr = POP_OBJECT();
 	    TclDecrRefCount(valuePtr);
 	}
@@ -7411,7 +7411,7 @@ TEBCresume(
 	    fprintf(stdout, "  ... found catch at %" TCL_Z_MODIFIER "u, catchTop=%d, "
 		    "unwound to %ld, new pc %" TCL_Z_MODIFIER "u\n",
 		    rangePtr->codeOffset, (int) (catchTop - initCatchTop - 1),
-		    (long)*catchTop, rangePtr->catchOffset);
+		    (long)PTR2INT(*catchTop), rangePtr->catchOffset);
 	}
 #endif
 	pc = (codePtr->codeStart + rangePtr->catchOffset);
-- 
2.34.GIT

