From a15b39e147800fd5617638bb0c8c36451aed90e8 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 11 Nov 2025 15:46:02 +0000 Subject: [PATCH 1/3] [librt] Support `librt.internal` API versioning with backward compatibility This lets us add new API features by adding more functions to the capsule and the module namespace without breaking backward compatibility. We shouldn't use the capsule if the installed version is too old, since we could be calling functions via uninitialized pointers. --- mypyc/lib-rt/librt_internal.c | 6 ++++++ mypyc/lib-rt/librt_internal.h | 25 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mypyc/lib-rt/librt_internal.c b/mypyc/lib-rt/librt_internal.c index ada2dfeb39a5..22d54de40f08 100644 --- a/mypyc/lib-rt/librt_internal.c +++ b/mypyc/lib-rt/librt_internal.c @@ -962,6 +962,11 @@ NativeInternal_ABI_Version(void) { return LIBRT_INTERNAL_ABI_VERSION; } +static int +NativeInternal_API_Version(void) { + return LIBRT_INTERNAL_API_VERSION; +} + static int librt_internal_module_exec(PyObject *m) { @@ -999,6 +1004,7 @@ librt_internal_module_exec(PyObject *m) (void *)cache_version_internal, (void *)ReadBuffer_type_internal, (void *)WriteBuffer_type_internal, + (void *)NativeInternal_API_Version, }; PyObject *c_api_object = PyCapsule_New((void *)NativeInternal_API, "librt.internal._C_API", NULL); if (PyModule_Add(m, "_C_API", c_api_object) < 0) { diff --git a/mypyc/lib-rt/librt_internal.h b/mypyc/lib-rt/librt_internal.h index bef9e196d2c1..bf551e6d1d47 100644 --- a/mypyc/lib-rt/librt_internal.h +++ b/mypyc/lib-rt/librt_internal.h @@ -1,8 +1,19 @@ #ifndef LIBRT_INTERNAL_H #define LIBRT_INTERNAL_H +// ABI version -- only an exact match is compatible. This will only be changed in +// very exceptional cases (likely never) due to strict backward compatiblity +// requirements. #define LIBRT_INTERNAL_ABI_VERSION 1 -#define LIBRT_INTERNAL_API_LEN 19 + +// API version -- more recent versions must maintain backward compatibility, i.e. +// we can add new features but not remove or change existing features (unless +// ABI version is changed, but see the comment above). + #define LIBRT_INTERNAL_API_VERSION 0 + +// Number of functions in the capsule API. If you add a new function, also increase +// LIBRT_INTERNAL_API_VERSION. +#define LIBRT_INTERNAL_API_LEN 20 #ifdef LIBRT_INTERNAL_MODULE @@ -27,6 +38,7 @@ static PyObject *read_bytes_internal(PyObject *data); static uint8_t cache_version_internal(void); static PyTypeObject *ReadBuffer_type_internal(void); static PyTypeObject *WriteBuffer_type_internal(void); +static int NativeInternal_API_Version(void); #else @@ -51,6 +63,7 @@ static void *NativeInternal_API[LIBRT_INTERNAL_API_LEN]; #define cache_version_internal (*(uint8_t (*)(void)) NativeInternal_API[16]) #define ReadBuffer_type_internal (*(PyTypeObject* (*)(void)) NativeInternal_API[17]) #define WriteBuffer_type_internal (*(PyTypeObject* (*)(void)) NativeInternal_API[18]) +#define NativeInternal_API_Version (*(int (*)(void)) NativeInternal_API[19]) static int import_librt_internal(void) @@ -72,6 +85,16 @@ import_librt_internal(void) PyErr_SetString(PyExc_ValueError, err); return -1; } + if (NativeInternal_API_Version() < LIBRT_INTERNAL_API_VERSION) { + char err[128]; + snprintf(err, sizeof(err), + "API version conflict for librt.internal, expected %d or newer, found %d (hint: upgrade librt)", + LIBRT_INTERNAL_API_VERSION, + NativeInternal_API_Version() + ); + PyErr_SetString(PyExc_ValueError, err); + return -1; + } return 0; } From 657463d7bb3867079dd2f30c40543b4d6eeaa97b Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 11 Nov 2025 16:00:11 +0000 Subject: [PATCH 2/3] Fix typo --- mypyc/lib-rt/librt_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/lib-rt/librt_internal.h b/mypyc/lib-rt/librt_internal.h index bf551e6d1d47..8fa72148af2c 100644 --- a/mypyc/lib-rt/librt_internal.h +++ b/mypyc/lib-rt/librt_internal.h @@ -2,7 +2,7 @@ #define LIBRT_INTERNAL_H // ABI version -- only an exact match is compatible. This will only be changed in -// very exceptional cases (likely never) due to strict backward compatiblity +// very exceptional cases (likely never) due to strict backward compatibility // requirements. #define LIBRT_INTERNAL_ABI_VERSION 1 From 00fae48201230f5f09afcf4eef620a04b5194734 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 11 Nov 2025 16:52:16 +0000 Subject: [PATCH 3/3] Update ABI version --- mypyc/lib-rt/librt_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/lib-rt/librt_internal.h b/mypyc/lib-rt/librt_internal.h index 8fa72148af2c..501162a27980 100644 --- a/mypyc/lib-rt/librt_internal.h +++ b/mypyc/lib-rt/librt_internal.h @@ -4,7 +4,7 @@ // ABI version -- only an exact match is compatible. This will only be changed in // very exceptional cases (likely never) due to strict backward compatibility // requirements. -#define LIBRT_INTERNAL_ABI_VERSION 1 +#define LIBRT_INTERNAL_ABI_VERSION 2 // API version -- more recent versions must maintain backward compatibility, i.e. // we can add new features but not remove or change existing features (unless