Skip to content

Commit 6455ebd

Browse files
committed
ensure correct alignment of PyInterpreterState when UBSan is on
1 parent a81232c commit 6455ebd

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

Include/pyport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,14 +664,17 @@ extern "C" {
664664
#if defined(__has_feature)
665665
# if __has_feature(undefined_behavior_sanitizer)
666666
# define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
667+
# define _Py_HAS_UNDEFINED_BEHAVIOR_SANITIZER
667668
# endif
668669
#endif
669670
#if !defined(_Py_NO_SANITIZE_UNDEFINED) && defined(__GNUC__) \
670671
&& ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))
671672
# define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
673+
# define _Py_HAS_UNDEFINED_BEHAVIOR_SANITIZER
672674
#endif
673675
#ifndef _Py_NO_SANITIZE_UNDEFINED
674676
# define _Py_NO_SANITIZE_UNDEFINED
677+
# undef _Py_HAS_UNDEFINED_BEHAVIOR_SANITIZER
675678
#endif
676679

677680

Python/pystate.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,11 +569,28 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
569569
return _PyStatus_OK();
570570
}
571571

572+
#ifdef _Py_HAS_UNDEFINED_BEHAVIOR_SANITIZER
573+
#define RAW_ALIGN_PTR_OFFSET sizeof(void *)
574+
#endif
572575

573-
static PyInterpreterState *
576+
static inline PyInterpreterState *
574577
alloc_interpreter(void)
575578
{
579+
#ifdef _Py_HAS_UNDEFINED_BEHAVIOR_SANITIZER
580+
size_t statesize = sizeof(PyInterpreterState);
581+
size_t alignment = _Alignof(PyInterpreterState);
582+
size_t allocsize = statesize + alignment - 1 + RAW_ALIGN_PTR_OFFSET;
583+
void *mem = PyMem_RawCalloc(1, allocsize);
584+
if (mem == NULL) {
585+
return NULL;
586+
}
587+
char *interp = _Py_ALIGN_UP((char *)mem + RAW_ALIGN_PTR_OFFSET, alignment);
588+
*(void **)(interp - RAW_ALIGN_PTR_OFFSET) = mem;
589+
assert(_Py_IS_ALIGNED(interp, alignment));
590+
return (PyInterpreterState *)interp;
591+
#else
576592
return PyMem_RawCalloc(1, sizeof(PyInterpreterState));
593+
#endif
577594
}
578595

579596
static void
@@ -587,12 +604,27 @@ free_interpreter(PyInterpreterState *interp)
587604
PyMem_RawFree(interp->obmalloc);
588605
interp->obmalloc = NULL;
589606
}
607+
#ifdef _Py_HAS_UNDEFINED_BEHAVIOR_SANITIZER
608+
assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState)));
609+
char *mem_location = (char *)interp - RAW_ALIGN_PTR_OFFSET;
610+
void *mem = *((void **)mem_location);
611+
if (mem != NULL) {
612+
PyMem_RawFree(mem);
613+
}
614+
#else
590615
PyMem_RawFree(interp);
616+
#endif
591617
}
592618
}
619+
620+
#ifdef _Py_HAS_UNDEFINED_BEHAVIOR_SANITIZER
621+
#undef RAW_ALIGN_PTR_OFFSET
622+
#endif
623+
593624
#ifndef NDEBUG
594625
static inline int check_interpreter_whence(long);
595626
#endif
627+
596628
/* Get the interpreter state to a minimal consistent state.
597629
Further init happens in pylifecycle.c before it can be used.
598630
All fields not initialized here are expected to be zeroed out,

0 commit comments

Comments
 (0)