Skip to content

Commit

Permalink
pythongh-109617: fix ncurses incompatibility on macOS with Xcode 15 (p…
Browse files Browse the repository at this point in the history
…ython#111258)

Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
  • Loading branch information
3 people authored and SonicField committed May 8, 2024
1 parent 8890b1f commit 027cd28
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 21 deletions.
19 changes: 14 additions & 5 deletions Include/py_curses.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@
# endif
#endif

#if !defined(HAVE_CURSES_IS_PAD) && defined(WINDOW_HAS_FLAGS)
/* The following definition is necessary for ncurses 5.7; without it,
some of [n]curses.h set NCURSES_OPAQUE to 1, and then Python
can't get at the WINDOW flags field. */
#if defined(WINDOW_HAS_FLAGS) && defined(__APPLE__)
/* gh-109617, gh-115383: we can rely on the default value for NCURSES_OPAQUE on
most platforms, but not on macOS. This is because, starting with Xcode 15,
Apple-provided ncurses.h comes from ncurses 6 (which defaults to opaque
structs) but can still be linked to older versions of ncurses dynamic
libraries which don't provide functions such as is_pad() to deal with opaque
structs. Setting NCURSES_OPAQUE to 0 is harmless in all ncurses releases to
this date (provided that a thread-safe implementation is not required), but
this might change in the future. This fix might become irrelevant once
support for macOS 13 or earlier is dropped. */
#define NCURSES_OPAQUE 0
#endif

Expand All @@ -39,7 +45,10 @@
#ifdef HAVE_NCURSES_H
/* configure was checking <curses.h>, but we will
use <ncurses.h>, which has some or all these features. */
#if !defined(WINDOW_HAS_FLAGS) && !(NCURSES_OPAQUE+0)
#if !defined(WINDOW_HAS_FLAGS) && \
(NCURSES_VERSION_PATCH+0 < 20070303 || !(NCURSES_OPAQUE+0))
/* the WINDOW flags field was always accessible in ncurses prior to 20070303;
after that, it depends on the value of NCURSES_OPAQUE. */
#define WINDOW_HAS_FLAGS 1
#endif
#if !defined(HAVE_CURSES_IS_PAD) && NCURSES_VERSION_PATCH+0 >= 20090906
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:mod:`ncurses`: fixed a crash that could occur on macOS 13 or earlier when
Python was built with Apple Xcode 15's SDK.
17 changes: 13 additions & 4 deletions Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1156,8 +1156,10 @@ int py_mvwdelch(WINDOW *w, int y, int x)
#endif

#if defined(HAVE_CURSES_IS_PAD)
// is_pad() is defined, either as a macro or as a function
#define py_is_pad(win) is_pad(win)
#elif defined(WINDOW_HAS_FLAGS)
// is_pad() is not defined, but we can inspect WINDOW structure members
#define py_is_pad(win) ((win) ? ((win)->_flags & _ISPAD) != 0 : FALSE)
#endif

Expand Down Expand Up @@ -4586,17 +4588,24 @@ make_ncurses_version(PyTypeObject *type)
if (ncurses_version == NULL) {
return NULL;
}

const char *str = curses_version();
unsigned long major = 0, minor = 0, patch = 0;
if (!str || sscanf(str, "%*[^0-9]%lu.%lu.%lu", &major, &minor, &patch) < 3) {
// Fallback to header version, which cannot be that wrong
major = NCURSES_VERSION_MAJOR;
minor = NCURSES_VERSION_MINOR;
patch = NCURSES_VERSION_PATCH;
}
#define SetIntItem(flag) \
PyStructSequence_SET_ITEM(ncurses_version, pos++, PyLong_FromLong(flag)); \
if (PyErr_Occurred()) { \
Py_CLEAR(ncurses_version); \
return NULL; \
}

SetIntItem(NCURSES_VERSION_MAJOR)
SetIntItem(NCURSES_VERSION_MINOR)
SetIntItem(NCURSES_VERSION_PATCH)
SetIntItem(major)
SetIntItem(minor)
SetIntItem(patch)
#undef SetIntItem

return ncurses_version;
Expand Down
55 changes: 44 additions & 11 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -6713,7 +6713,10 @@ AC_DEFUN([PY_CHECK_CURSES_FUNC],
[py_var],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[@%:@include <curses.h>], [
[
#define NCURSES_OPAQUE 0
#include <curses.h>
], [
#ifndef $1
void *x=$1
#endif
Expand Down

0 comments on commit 027cd28

Please sign in to comment.