Skip to content

Commit d566a2d

Browse files
authored
more cleanup of private FFI definitions (#6042)
* more cleanup of private FFI definitions * newsfragment * remove incorrect exclusions * fixup clippy * fixup exclusions * fix missing x86 link name
1 parent c5a34b6 commit d566a2d

9 files changed

Lines changed: 62 additions & 20 deletions

File tree

newsfragments/6042.removed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove private FFI definitions `_PyBytes_Resize` and `_PyErr_BadInternalCall`.

noxfile.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,13 @@ def load_pkg_versions():
12031203

12041204
@nox.session(name="ffi-check")
12051205
def ffi_check(session: nox.Session):
1206-
_run_cargo(session, "run", _FFI_CHECK, "--message-format=short")
1206+
extra_args = []
1207+
# This flag can be useful for debugging ffi-check errors, but overall the
1208+
# short message format is easier to read
1209+
if "--long-message-format" not in session.posargs:
1210+
extra_args.append("--message-format=short")
1211+
1212+
_run_cargo(session, "run", _FFI_CHECK, *extra_args)
12071213
_check_raw_dylib_macro(session)
12081214

12091215

pyo3-ffi-check/build.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ fn main() {
1010
// write docs into the build script output directory, they will be read
1111
// by the proc macro to resolve what definitions exist
1212
let status = std::process::Command::new("cargo")
13-
.args(["doc", "-p", "pyo3-ffi-check-definitions", "--no-deps"])
13+
.args([
14+
"doc",
15+
"-p",
16+
"pyo3-ffi-check-definitions",
17+
"--no-deps",
18+
"--document-private-items",
19+
])
1420
.env("CARGO_TARGET_DIR", out_dir)
1521
// forward target to the doc buid to ensure `--target` is honored
1622
.env("CARGO_BUILD_TARGET", target)

pyo3-ffi-check/macro/src/lib.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,17 @@ pub fn for_all_fields(input: proc_macro::TokenStream) -> proc_macro::TokenStream
155155
}
156156

157157
let pyo3_ffi_fields = get_fields_from_file(&pyo3_ffi_struct_file);
158-
let bindgen_fields = get_fields_from_file(&bindgen_struct_file);
159158

160-
if pyo3_ffi_fields.is_empty() {
161-
// probably an opaque type on PyO3 side, skip
159+
if pyo3_ffi_fields.len() == 2
160+
&& pyo3_ffi_fields.contains(&"_data".to_string())
161+
&& pyo3_ffi_fields.contains(&"_marker".to_string())
162+
{
163+
// looks like an opaque type on the PyO3 side, skip
162164
return TokenStream::new().into();
163165
}
164166

167+
let bindgen_fields = get_fields_from_file(&bindgen_struct_file);
168+
165169
let mut all_fields: HashSet<_> = pyo3_ffi_fields.into_iter().chain(bindgen_fields).collect();
166170

167171
if struct_name == "PyMemberDef" {
@@ -425,9 +429,11 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[
425429
("Py_False", ""),
426430
("Py_GETENV", "not(Py_3_11)"),
427431
("Py_INCREF", ""),
432+
("Py_IS_TYPE", "not(Py_3_15)"), // symbol added for stable abi on 3.15
428433
("Py_None", ""),
429434
("Py_NotImplemented", ""),
430435
("Py_REFCNT", "not(Py_3_14)"),
436+
("Py_SIZE", "not(Py_3_15)"), // symbol added for stable abi on 3.15
431437
("Py_True", ""),
432438
("Py_TYPE", "not(Py_3_14)"),
433439
("Py_UNICODE_TODECIMAL", ""),
@@ -476,9 +482,6 @@ const EXCLUDED_SYMBOLS: &[&str] = &[
476482
"PyOS_BeforeFork",
477483
"PyOS_AfterFork_Parent",
478484
"PyOS_AfterFork_Child",
479-
// See https://github.com/python/cpython/pull/139166/changes#r3214904694
480-
"Py_IS_TYPE",
481-
"Py_SIZE",
482485
];
483486

484487
// Assert at compile time that `MACRO_EXCLUSIONS` and `EXCLUDED_SYMBOLS` are disjoint
@@ -718,9 +721,11 @@ fn get_function_info(
718721
static FUNCTION_DECL_REGEX: LazyLock<regex::Regex> =
719722
LazyLock::new(|| regex::Regex::new(r"^pub\s+(.*?)\sfn\s+([^(<]*)").unwrap());
720723

721-
let captures = FUNCTION_DECL_REGEX
722-
.captures(&text)
723-
.expect("failed to parse function declaration with regex");
724+
let Some(captures) = FUNCTION_DECL_REGEX.captures(&text) else {
725+
panic!(
726+
"failed to parse function declaration for `{function_name}` with regex, got: {text}"
727+
);
728+
};
724729

725730
// find modifiers, e.g. `unsafe extern "C"`
726731
let modifiers = captures.get(1).unwrap().as_str().parse().unwrap();

pyo3-ffi/src/cpython/bytesobject.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ opaque_struct!(pub PyBytesObject);
2323

2424
extern_libpython! {
2525
#[cfg_attr(PyPy, link_name = "_PyPyBytes_Resize")]
26-
pub fn _PyBytes_Resize(bytes: *mut *mut PyObject, newsize: Py_ssize_t) -> c_int;
26+
pub(crate) fn _PyBytes_Resize(bytes: *mut *mut PyObject, newsize: Py_ssize_t) -> c_int;
2727
}
2828

2929
#[cfg(not(Py_LIMITED_API))]

pyo3-ffi/src/cpython/traceback.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use core::ffi::c_int;
44

55
#[repr(C)]
66
pub struct PyTracebackObject {
7-
ob_base: PyObject,
8-
tb_next: *mut PyTracebackObject,
9-
tb_frame: *mut PyFrameObject,
10-
tb_lasti: c_int,
11-
tb_lineno: c_int,
7+
pub ob_base: PyObject,
8+
pub tb_next: *mut PyTracebackObject,
9+
pub tb_frame: *mut PyFrameObject,
10+
pub tb_lasti: c_int,
11+
pub tb_lineno: c_int,
1212
}

pyo3-ffi/src/impl_/macros.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ macro_rules! extern_libpython_maybe_private_fn {
158158
) => {
159159
extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? }
160160
};
161+
(
162+
[_PyErr_BadInternalCall]
163+
$(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)?
164+
) => {
165+
extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? }
166+
};
161167
(
162168
[$name:ident]
163169
$(#[$attrs:meta])* $vis:vis fn $fn_name:ident($($args:tt)*) $(-> $ret:ty)?

pyo3-ffi/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@
377377
// original CPython headers
378378
#![allow(unsafe_op_in_unsafe_fn)]
379379

380-
#[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG"))]
380+
#[cfg(not(PyPy))]
381381
extern crate alloc;
382382
#[cfg(not(any(Py_3_14, target_arch = "wasm32")))]
383383
extern crate std;
@@ -389,7 +389,10 @@ macro_rules! opaque_struct {
389389
($(#[$attrs:meta])* $pub:vis $name:ident) => {
390390
$(#[$attrs])*
391391
#[repr(C)]
392-
$pub struct $name([u8; 0]);
392+
$pub struct $name {
393+
_data: (),
394+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
395+
}
393396
};
394397
}
395398

pyo3-ffi/src/pyerrors.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,24 @@ extern_libpython! {
310310
arg2: *mut PyObject,
311311
arg3: *mut PyObject,
312312
) -> *mut PyObject;
313+
#[cfg(PyPy)]
313314
#[cfg_attr(PyPy, link_name = "PyPyErr_BadInternalCall")]
314315
pub fn PyErr_BadInternalCall();
315-
// skipped _PyErr_BadInternalCall
316+
317+
#[cfg(not(PyPy))]
318+
fn _PyErr_BadInternalCall(filename: *const c_char, lineno: c_int);
319+
}
320+
321+
#[cfg(not(PyPy))]
322+
#[track_caller]
323+
#[inline]
324+
pub unsafe fn PyErr_BadInternalCall() {
325+
let location = core::panic::Location::caller();
326+
let filename = alloc::ffi::CString::new(location.file()).unwrap();
327+
unsafe { _PyErr_BadInternalCall(filename.as_ptr(), location.line() as c_int) }
328+
}
329+
330+
extern_libpython! {
316331
#[cfg_attr(PyPy, link_name = "PyPyErr_NewException")]
317332
pub fn PyErr_NewException(
318333
name: *const c_char,

0 commit comments

Comments
 (0)