diff -r 2df462852464 Include/asdl.h --- a/Include/asdl.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Include/asdl.h Thu Jan 21 13:58:36 2016 +0200 @@ -17,12 +17,12 @@ typedef struct { Py_ssize_t size; - void *elements[1]; + void *elements[1] Py_VARIABLE_SIZE; } asdl_seq; typedef struct { Py_ssize_t size; - int elements[1]; + int elements[1] Py_VARIABLE_SIZE; } asdl_int_seq; asdl_seq *_Py_asdl_seq_new(Py_ssize_t size, PyArena *arena); diff -r 2df462852464 Include/bytesobject.h --- a/Include/bytesobject.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Include/bytesobject.h Thu Jan 21 13:58:36 2016 +0200 @@ -31,7 +31,7 @@ typedef struct { PyObject_VAR_HEAD Py_hash_t ob_shash; - char ob_sval[1]; + char ob_sval[1] Py_VARIABLE_SIZE; /* Invariants: * ob_sval contains space for 'ob_size+1' elements. diff -r 2df462852464 Include/frameobject.h --- a/Include/frameobject.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Include/frameobject.h Thu Jan 21 13:58:36 2016 +0200 @@ -49,7 +49,7 @@ int f_iblock; /* index in f_blockstack */ char f_executing; /* whether the frame is still executing */ PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ - PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */ + PyObject *f_localsplus[1] Py_VARIABLE_SIZE; /* locals+stack, dynamically sized */ } PyFrameObject; diff -r 2df462852464 Include/longintrepr.h --- a/Include/longintrepr.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Include/longintrepr.h Thu Jan 21 13:58:36 2016 +0200 @@ -87,8 +87,8 @@ */ struct _longobject { - PyObject_VAR_HEAD - digit ob_digit[1]; + PyObject_VAR_HEAD + digit ob_digit[1] Py_VARIABLE_SIZE; }; PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); diff -r 2df462852464 Include/memoryobject.h --- a/Include/memoryobject.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Include/memoryobject.h Thu Jan 21 13:58:36 2016 +0200 @@ -60,7 +60,7 @@ Py_ssize_t exports; /* number of buffer re-exports */ Py_buffer view; /* private copy of the exporter's view */ PyObject *weakreflist; - Py_ssize_t ob_array[1]; /* shape, strides, suboffsets */ + Py_ssize_t ob_array[1] Py_VARIABLE_SIZE; /* shape, strides, suboffsets */ } PyMemoryViewObject; #endif diff -r 2df462852464 Include/pyport.h --- a/Include/pyport.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Include/pyport.h Thu Jan 21 13:58:36 2016 +0200 @@ -897,4 +897,38 @@ #endif /* _MSC_VER >= 1900 */ #endif /* Py_BUILD_CORE */ +/* + * Check for MPX support. GCC 5.3 or higher is needed for the MPX + * attributes to be supported. + * + * Py_BND_LEGACY - function attribute that disables instrumentation for that + * function and sub-calls + * Py_VARIABLE_SIZE - attribute that marks variable sized fields in objects + * Py_INIT_BOUNDS(p) - return new pointer with the value of p and no bounds. + * When instrumentation is disabled, returns p + * Py_SET_PTR_BOUNDS(p, size) - return new pointer with the value of p and + * bounds [p, p+size-1]. When instrumentation is + * disabled, returns p + * Py_COPY_PTR_BOUNDS(p, q) - return new pointer with the value of p and + * associate it with the bounds of q. Returns p when + * instrumentation is disabled + */ + +#if defined(__GNUC__) && ((__GNUC__ >= 6) || \ + (__GNUC__ == 5) && (__GNUC_MINOR__ >= 3)) && \ + defined(Py_INTEL_MPX) +#define Py_BND_LEGACY __attribute__((bnd_legacy)) +#define Py_VARIABLE_SIZE __attribute__((bnd_variable_size)) +#define Py_INIT_BOUNDS(p) __bnd_init_ptr_bounds(p) +#define Py_SET_PTR_BOUNDS(p, size) __bnd_set_ptr_bounds(p, size) +#define Py_COPY_PTR_BOUNDS(p, q) __bnd_copy_ptr_bounds(p, q) +#define Py_MPX_ENABLED +#else +#define Py_BND_LEGACY +#define Py_VARIABLE_SIZE +#define Py_INIT_BOUNDS(p) (p) +#define Py_SET_PTR_BOUNDS(p, size) (p) +#define Py_COPY_PTR_BOUNDS(p, q) (p) +#endif + #endif /* Py_PYPORT_H */ diff -r 2df462852464 Include/tupleobject.h --- a/Include/tupleobject.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Include/tupleobject.h Thu Jan 21 13:58:36 2016 +0200 @@ -24,7 +24,7 @@ #ifndef Py_LIMITED_API typedef struct { PyObject_VAR_HEAD - PyObject *ob_item[1]; + PyObject *ob_item[1] Py_VARIABLE_SIZE; /* ob_item contains space for 'ob_size' elements. * Items must normally not be NULL, except during construction when diff -r 2df462852464 Makefile.pre.in --- a/Makefile.pre.in Wed Jan 20 22:25:40 2016 -0800 +++ b/Makefile.pre.in Thu Jan 21 13:58:36 2016 +0200 @@ -80,6 +80,7 @@ # Use it when a compiler flag should _not_ be part of the distutils CFLAGS # once Python is installed (Issue #21121). CONFIGURE_CFLAGS_NODIST=@CFLAGS_NODIST@ +CONFIGURE_LDFLAGS_NODIST=@LDFLAGS_NODIST@ CONFIGURE_CPPFLAGS= @CPPFLAGS@ CONFIGURE_LDFLAGS= @LDFLAGS@ # Avoid assigning CFLAGS, LDFLAGS, etc. so users can use them on the @@ -91,7 +92,7 @@ # be able to build extension modules using the directories specified in the # environment variables PY_CPPFLAGS= $(BASECPPFLAGS) -I. -IInclude -I$(srcdir)/Include $(CONFIGURE_CPPFLAGS) $(CPPFLAGS) -PY_LDFLAGS= $(CONFIGURE_LDFLAGS) $(LDFLAGS) +PY_LDFLAGS= $(CONFIGURE_LDFLAGS) $(LDFLAGS) $(CONFIGURE_LDFLAGS_NODIST) NO_AS_NEEDED= @NO_AS_NEEDED@ LDLAST= @LDLAST@ SGI_ABI= @SGI_ABI@ diff -r 2df462852464 Modules/_ctypes/ctypes.h --- a/Modules/_ctypes/ctypes.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Modules/_ctypes/ctypes.h Thu Jan 21 13:58:36 2016 +0200 @@ -67,7 +67,7 @@ PyObject *restype; SETFUNC setfunc; ffi_type *ffi_restype; - ffi_type *atypes[1]; + ffi_type *atypes[1] Py_VARIABLE_SIZE; } CThunkObject; extern PyTypeObject PyCThunk_Type; #define CThunk_CheckExact(v) ((v)->ob_type == &PyCThunk_Type) diff -r 2df462852464 Modules/_tracemalloc.c --- a/Modules/_tracemalloc.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Modules/_tracemalloc.c Thu Jan 21 13:58:36 2016 +0200 @@ -72,7 +72,7 @@ typedef struct { Py_uhash_t hash; int nframe; - frame_t frames[1]; + frame_t frames[1] Py_VARIABLE_SIZE; } traceback_t; #define TRACEBACK_SIZE(NFRAME) \ diff -r 2df462852464 Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Modules/expat/xmlparse.c Thu Jan 21 13:58:36 2016 +0200 @@ -24,6 +24,7 @@ #include "ascii.h" #include "expat.h" +#include "pyport.h" #ifdef XML_UNICODE #define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX @@ -217,7 +218,7 @@ typedef struct block { struct block *next; int size; - XML_Char s[1]; + XML_Char s[1] Py_VARIABLE_SIZE; } BLOCK; typedef struct { diff -r 2df462852464 Modules/faulthandler.c --- a/Modules/faulthandler.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Modules/faulthandler.c Thu Jan 21 13:58:36 2016 +0200 @@ -391,6 +391,10 @@ for (i=0; i < faulthandler_nsignals; i++) { handler = &faulthandler_handlers[i]; +#ifdef Py_MPX_ENABLED + if (handler->signum == SIGSEGV) + continue; +#endif #ifdef HAVE_SIGACTION action.sa_handler = faulthandler_fatal_error; sigemptyset(&action.sa_mask); diff -r 2df462852464 Modules/gcmodule.c --- a/Modules/gcmodule.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Modules/gcmodule.c Thu Jan 21 13:58:36 2016 +0200 @@ -1708,7 +1708,7 @@ collect_generations(); collecting = 0; } - op = FROM_GC(g); + op = Py_COPY_PTR_BOUNDS(FROM_GC(g), g); return op; } @@ -1760,7 +1760,7 @@ g = (PyGC_Head *)PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize); if (g == NULL) return (PyVarObject *)PyErr_NoMemory(); - op = (PyVarObject *) FROM_GC(g); + op = (PyVarObject *) Py_COPY_PTR_BOUNDS(FROM_GC(g), g); Py_SIZE(op) = nitems; return op; } diff -r 2df462852464 Modules/sre.h --- a/Modules/sre.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Modules/sre.h Thu Jan 21 13:58:36 2016 +0200 @@ -36,7 +36,7 @@ int isbytes; /* pattern type (1 - bytes, 0 - string, -1 - None) */ /* pattern code */ Py_ssize_t codesize; - SRE_CODE code[1]; + SRE_CODE code[1] Py_VARIABLE_SIZE; } PatternObject; #define PatternObject_GetCode(o) (((PatternObject*)(o))->code) @@ -49,7 +49,7 @@ Py_ssize_t pos, endpos; /* current target slice */ Py_ssize_t lastindex; /* last index marker seen by the engine (-1 if none) */ Py_ssize_t groups; /* number of groups (start/end marks) */ - Py_ssize_t mark[1]; + Py_ssize_t mark[1] Py_VARIABLE_SIZE; } MatchObject; typedef unsigned int (*SRE_TOLOWER_HOOK)(unsigned int ch); diff -r 2df462852464 Modules/winreparse.h --- a/Modules/winreparse.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Modules/winreparse.h Thu Jan 21 13:58:36 2016 +0200 @@ -23,7 +23,7 @@ USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; - WCHAR PathBuffer[1]; + WCHAR PathBuffer[1] Py_VARIABLE_SIZE; } SymbolicLinkReparseBuffer; struct { @@ -31,11 +31,11 @@ USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; - WCHAR PathBuffer[1]; + WCHAR PathBuffer[1] Py_VARIABLE_SIZE; } MountPointReparseBuffer; struct { - UCHAR DataBuffer[1]; + UCHAR DataBuffer[1] Py_VARIABLE_SIZE; } GenericReparseBuffer; }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; diff -r 2df462852464 Objects/dict-common.h --- a/Objects/dict-common.h Wed Jan 20 22:25:40 2016 -0800 +++ b/Objects/dict-common.h Thu Jan 21 13:58:36 2016 +0200 @@ -16,7 +16,7 @@ Py_ssize_t dk_size; dict_lookup_func dk_lookup; Py_ssize_t dk_usable; - PyDictKeyEntry dk_entries[1]; + PyDictKeyEntry dk_entries[1] Py_VARIABLE_SIZE; }; #endif diff -r 2df462852464 Objects/dictobject.c --- a/Objects/dictobject.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Objects/dictobject.c Thu Jan 21 13:58:36 2016 +0200 @@ -1785,7 +1785,7 @@ offset = sizeof(PyObject *); } else { - value_ptr = &ep[0].me_value; + value_ptr = Py_COPY_PTR_BOUNDS(&ep[0].me_value, mp->ma_keys); offset = sizeof(PyDictKeyEntry); } for (i = 0, j = 0; i < size; i++) { @@ -1808,6 +1808,7 @@ Py_ssize_t i, j; Py_ssize_t size, n, offset; PyObject **value_ptr; + PyDictKeyEntry *ep; again: n = mp->ma_used; @@ -1822,12 +1823,13 @@ goto again; } size = DK_SIZE(mp->ma_keys); + ep = &mp->ma_keys->dk_entries[0]; if (mp->ma_values) { value_ptr = mp->ma_values; offset = sizeof(PyObject *); } else { - value_ptr = &mp->ma_keys->dk_entries[0].me_value; + value_ptr = Py_COPY_PTR_BOUNDS(&ep[0].me_value, mp->ma_keys); offset = sizeof(PyDictKeyEntry); } for (i = 0, j = 0; i < size; i++) { @@ -1885,7 +1887,7 @@ offset = sizeof(PyObject *); } else { - value_ptr = &ep[0].me_value; + value_ptr = Py_COPY_PTR_BOUNDS(&ep[0].me_value, mp->ma_keys); offset = sizeof(PyDictKeyEntry); } for (i = 0, j = 0; i < size; i++) { diff -r 2df462852464 Objects/listobject.c --- a/Objects/listobject.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Objects/listobject.c Thu Jan 21 13:58:36 2016 +0200 @@ -1090,11 +1090,12 @@ *p = *(p-1); *l = pivot; if (lo.values != NULL) { - Py_ssize_t offset = lo.values - lo.keys; - p = start + offset; + Py_ssize_t offset = start - lo.keys; + Py_ssize_t l_offset = l - lo.keys; + p = lo.values + offset; pivot = *p; - l += offset; - for (p = start + offset; p > l; --p) + l = lo.values + l_offset; + for (p = lo.values + offset; p > l; --p) *p = *(p-1); *l = pivot; } diff -r 2df462852464 Objects/memoryobject.c --- a/Objects/memoryobject.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Objects/memoryobject.c Thu Jan 21 13:58:36 2016 +0200 @@ -964,7 +964,7 @@ typedef struct { Py_buffer view; - Py_ssize_t array[1]; + Py_ssize_t array[1] Py_VARIABLE_SIZE; } Py_buffer_full; int diff -r 2df462852464 Objects/obmalloc.c --- a/Objects/obmalloc.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Objects/obmalloc.c Thu Jan 21 13:58:36 2016 +0200 @@ -722,7 +722,7 @@ #define DUMMY_SIZE_IDX 0xffff /* size class of newly cached pools */ /* Round pointer P down to the closest pool-aligned address <= P, as a poolp */ -#define POOL_ADDR(P) ((poolp)_Py_ALIGN_DOWN((P), POOL_SIZE)) +#define POOL_ADDR(P) ((poolp)Py_SET_PTR_BOUNDS(_Py_ALIGN_DOWN((P), POOL_SIZE), POOL_SIZE)) /* Return total number of blocks in pool of size index I, as a uint. */ #define NUMBLOCKS(I) ((uint)(POOL_SIZE - POOL_OVERHEAD) / INDEX2SIZE(I)) @@ -1208,7 +1208,7 @@ UNLOCK(); if (use_calloc) memset(bp, 0, nbytes); - return (void *)bp; + return (void *)Py_SET_PTR_BOUNDS(bp, INDEX2SIZE(size)); } /* * Reached the end of the free list, try to extend it. @@ -1222,7 +1222,7 @@ UNLOCK(); if (use_calloc) memset(bp, 0, nbytes); - return (void *)bp; + return (void *)Py_SET_PTR_BOUNDS(bp, INDEX2SIZE(size)); } /* Pool is full, unlink from used pools. */ next = pool->nextpool; @@ -1232,7 +1232,7 @@ UNLOCK(); if (use_calloc) memset(bp, 0, nbytes); - return (void *)bp; + return (void *)Py_SET_PTR_BOUNDS(bp, INDEX2SIZE(size)); } /* There isn't a pool of the right size class immediately @@ -1313,7 +1313,7 @@ UNLOCK(); if (use_calloc) memset(bp, 0, nbytes); - return (void *)bp; + return (void *)Py_SET_PTR_BOUNDS(bp, INDEX2SIZE(size)); } /* * Initialize the pool header, set up the free list to @@ -1330,7 +1330,7 @@ UNLOCK(); if (use_calloc) memset(bp, 0, nbytes); - return (void *)bp; + return (void *)Py_SET_PTR_BOUNDS(bp, size); } /* Carve off a new pool. */ diff -r 2df462852464 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Objects/unicodeobject.c Thu Jan 21 13:58:36 2016 +0200 @@ -7958,7 +7958,7 @@ PyObject_HEAD unsigned char level1[32]; int count2, count3; - unsigned char level23[1]; + unsigned char level23[1] Py_VARIABLE_SIZE; }; static PyObject* diff -r 2df462852464 Python/dtoa.c --- a/Python/dtoa.c Wed Jan 20 22:25:40 2016 -0800 +++ b/Python/dtoa.c Thu Jan 21 13:58:36 2016 +0200 @@ -330,7 +330,7 @@ Bigint { struct Bigint *next; int k, maxwds, sign, wds; - ULong x[1]; + ULong x[1] Py_VARIABLE_SIZE; }; typedef struct Bigint Bigint; diff -r 2df462852464 configure --- a/configure Wed Jan 20 22:25:40 2016 -0800 +++ b/configure Thu Jan 21 13:58:36 2016 +0200 @@ -664,6 +664,7 @@ LIBTOOL_CRUFT OTHER_LIBTOOL_OPT UNIVERSAL_ARCH_FLAGS +LDFLAGS_NODIST CFLAGS_NODIST BASECFLAGS OPT @@ -807,6 +808,7 @@ enable_shared enable_profiling with_pydebug +with_mpx with_hash_algorithm with_address_sanitizer with_libs @@ -1487,6 +1489,8 @@ compiler --with-suffix=.exe set executable suffix --with-pydebug build with Py_DEBUG defined + --with-mpx Enable Intel MPX (Memory Protection Extensions) + feature. Disabled by default. --with-hash-algorithm=[fnv|siphash24] select hash algorithm --with-address-sanitizer @@ -6560,6 +6564,52 @@ fi +# Check for --with-mpx +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-mpx" >&5 +$as_echo_n "checking for --with-mpx... " >&6; } + +# Check whether --with-mpx was given. +if test "${with_mpx+set}" = set; then : + withval=$with_mpx; +if test "$withval" != no +then + mpx_compatible=false + if [ "$CC" = "gcc" ] + then + CC_MAJOR_VERSION=$(gcc -dumpversion | cut -f1 -d.) + CC_MINOR_VERSION=$(gcc -dumpversion | cut -f2 -d.) + if [ "$CC_MAJOR_VERSION" -ge "5" ] + then + mpx_compatible=true + if [ "$CC_MAJOR_VERSION" -eq "5" ] && [ "$CC_MINOR_VERSION" -lt "3" ] + then + mpx_compatible=false + fi + fi + fi + + if [ "$mpx_compatible" = "false" ] + then + as_fn_error $? "MPX feature can only be used with gcc 5.3 and higher" "$LINENO" 5 + else + +$as_echo "#define Py_INTEL_MPX 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + CFLAGS_NODIST="$CFLAGS_NODIST -fcheck-pointer-bounds -mmpx" + LDFLAGS_NODIST="$LDFLAGS_NODIST -fcheck-pointer-bounds -mmpx" + OPT="-g -O3 -fno-ipa-icf -Wall $STRICT_PROTO" + fi +else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Enable PGO flags. diff -r 2df462852464 configure.ac --- a/configure.ac Wed Jan 20 22:25:40 2016 -0800 +++ b/configure.ac Thu Jan 21 13:58:36 2016 +0200 @@ -1235,6 +1235,43 @@ fi], [AC_MSG_RESULT(no)]) +# Check for --with-mpx +AC_MSG_CHECKING(for --with-mpx) +AC_ARG_WITH(mpx, + AS_HELP_STRING([--with-mpx], [Enable Intel MPX (Memory Protection Extensions) + feature. Disabled by default.]), +[ +if test "$withval" != no +then + mpx_compatible=false + if [[ "$CC" = "gcc" ]] + then + CC_MAJOR_VERSION=$(gcc -dumpversion | cut -f1 -d.) + CC_MINOR_VERSION=$(gcc -dumpversion | cut -f2 -d.) + if [[ "$CC_MAJOR_VERSION" -ge "5" ]] + then + mpx_compatible=true + if [[ "$CC_MAJOR_VERSION" -eq "5" ]] && [[ "$CC_MINOR_VERSION" -lt "3" ]] + then + mpx_compatible=false + fi + fi + fi + + if [[ "$mpx_compatible" = "false" ]] + then + AC_MSG_ERROR([MPX feature can only be used with gcc 5.3 and higher]) + else + AC_DEFINE(Py_INTEL_MPX, 1, [Define if you want to build an MPX instrumented interpreter.]) + AC_MSG_RESULT(yes); + CFLAGS_NODIST="$CFLAGS_NODIST -fcheck-pointer-bounds -mmpx" + LDFLAGS_NODIST="$LDFLAGS_NODIST -fcheck-pointer-bounds -mmpx" + OPT="-g -O3 -fno-ipa-icf -Wall $STRICT_PROTO" + fi +else AC_MSG_RESULT(no) +fi], +[AC_MSG_RESULT(no)]) + # Enable PGO flags. AC_SUBST(PGO_PROF_GEN_FLAG) AC_SUBST(PGO_PROF_USE_FLAG) @@ -1350,6 +1387,7 @@ AC_SUBST(BASECFLAGS) AC_SUBST(CFLAGS_NODIST) +AC_SUBST(LDFLAGS_NODIST) # The -arch flags for universal builds on OSX UNIVERSAL_ARCH_FLAGS= diff -r 2df462852464 pyconfig.h.in --- a/pyconfig.h.in Wed Jan 20 22:25:40 2016 -0800 +++ b/pyconfig.h.in Thu Jan 21 13:58:36 2016 +0200 @@ -1239,6 +1239,9 @@ externally defined: 0 */ #undef Py_HASH_ALGORITHM +/* Define if you want to build an MPX instrumented interpreter. */ +#undef Py_INTEL_MPX + /* assume C89 semantics that RETSIGTYPE is always void */ #undef RETSIGTYPE