]> git.eshelyaron.com Git - emacs.git/commitdiff
Don't use pointer arithmetic for untagging Lisp values (bug#65491)
authorMattias Engdegård <mattiase@acm.org>
Mon, 28 Aug 2023 09:13:10 +0000 (11:13 +0200)
committerMattias Engdegård <mattiase@acm.org>
Mon, 18 Sep 2023 18:06:01 +0000 (20:06 +0200)
* src/lisp.h (XUNTAG):
Instead of casting a Lisp value to char * and subtracting the tag,
cast it to a suitable integral type and work on that.

This should result in identical or at least equivalent code, except
that it avoids potential problems arising from the restrictions on
pointer arithmetic in C.  In particular, a null pointer can be neither
an operand in nor the result of pointer arithmetic.

C compilers know this and would, prior to this change, optimise

  XUNTAG(obj, Lisp_Int0, mytype) != NULL

to 1.  This means, for example, that make_pointer_integer and
XFIXNUMPTR could not be entrusted with null pointers, and
next_vector in alloc.c was unsafe to use.

src/lisp.h

index 50b68f2e7678833e2b91dfd5dcb0f4aaa9603eaf..de6746f1c07b5809bbc56af1699c04f66a74b721 100644 (file)
@@ -808,10 +808,12 @@ INLINE void
 }
 
 /* Extract A's pointer value, assuming A's Lisp type is TYPE and the
-   extracted pointer's type is CTYPE *.  */
-
-#define XUNTAG(a, type, ctype) ((ctype *) \
-                               ((char *) XLP (a) - LISP_WORD_TAG (type)))
+   extracted pointer's type is CTYPE *.
+   Note that the second term vanishes if EMACS_INT is wider than pointers
+   and the tag is in the upper bits (ie, USE_LSB_TAG=0); this makes
+   untagging slightly cheaper in that case.  */
+#define XUNTAG(a, type, ctype) \
+  ((ctype *) ((uintptr_t) XLP (a) - (uintptr_t) LISP_WORD_TAG (type)))
 
 /* A forwarding pointer to a value.  It uses a generic pointer to
    avoid alignment bugs that could occur if it used a pointer to a