From 0d17190cc821ee5ce1c1bf6ddafaeeebb2c3f463 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 3 Jan 2025 13:02:20 +0200 Subject: [PATCH 1/2] gh-123681: Check the strftime() behavior at runtime instead of at the compile time It is needed to support cross-compiling. Remove macros Py_NORMALIZE_CENTURY and Py_STRFTIME_C99_SUPPORT. --- ...-01-03-13-02-06.gh-issue-123681.gQ67nK.rst | 3 + Modules/_datetimemodule.c | 50 +++++++-- configure | 104 ------------------ configure.ac | 56 ---------- pyconfig.h.in | 6 - 5 files changed, 42 insertions(+), 177 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2025-01-03-13-02-06.gh-issue-123681.gQ67nK.rst diff --git a/Misc/NEWS.d/next/Build/2025-01-03-13-02-06.gh-issue-123681.gQ67nK.rst b/Misc/NEWS.d/next/Build/2025-01-03-13-02-06.gh-issue-123681.gQ67nK.rst new file mode 100644 index 00000000000000..8f4f1fb4fabbe5 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2025-01-03-13-02-06.gh-issue-123681.gQ67nK.rst @@ -0,0 +1,3 @@ +Check the ``strftime()`` behavior at runtime instead of at the compile time +to support cross-compiling. Remove macros Py_NORMALIZE_CENTURY and +Py_STRFTIME_C99_SUPPORT. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index b1102984cb5e9e..04b256edd88498 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1740,6 +1740,42 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, return 0; } +/* Check whether year with century should be normalized for strftime. */ +inline static int +normalize_century(void) +{ + static int _normalize_century = -1; + if (_normalize_century < 0) { + char year[5]; + struct tm date = { + .tm_year = -1801, + .tm_mon = 0, + .tm_mday = 1 + }; + _normalize_century = (strftime(year, sizeof(year), "%Y", &date) && + strcmp(year, "0099") != 0); + } + return _normalize_century; +} + +/* Check whether C99-specific strftime specifiers are supported. */ +inline static int +strftime_c99_support(void) +{ + static int _strftime_c99_support = -1; + if (_strftime_c99_support < 0) { + char full_date[11]; + struct tm date = { + .tm_year = 0, + .tm_mon = 0, + .tm_mday = 1 + }; + _strftime_c99_support = (strftime(full_date, sizeof(full_date), "%F", &date) && + strcmp(full_date, "1900-01-01") == 0); + } + return _strftime_c99_support; +} + static PyObject * make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) { @@ -1910,12 +1946,9 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, } replacement = freplacement; } -#ifdef Py_NORMALIZE_CENTURY - else if (ch == 'Y' || ch == 'G' -#ifdef Py_STRFTIME_C99_SUPPORT - || ch == 'F' || ch == 'C' -#endif - ) { + else if (normalize_century() && (ch == 'Y' || ch == 'G' || + (strftime_c99_support() && (ch == 'F' || ch == 'C')))) + { /* 0-pad year with century as necessary */ PyObject *item = PySequence_GetItem(timetuple, 0); if (item == NULL) { @@ -1952,15 +1985,11 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, * +6 to accommodate dashes, 2-digit month and day for %F. */ char buf[SIZEOF_LONG * 5 / 2 + 2 + 6]; Py_ssize_t n = PyOS_snprintf(buf, sizeof(buf), -#ifdef Py_STRFTIME_C99_SUPPORT ch == 'F' ? "%04ld-%%m-%%d" : -#endif "%04ld", year_long); -#ifdef Py_STRFTIME_C99_SUPPORT if (ch == 'C') { n -= 2; } -#endif if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { goto Error; } @@ -1970,7 +1999,6 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, } continue; } -#endif else { /* percent followed by something else */ continue; diff --git a/configure b/configure index 3d2c60213db591..9f67c9ead085dd 100755 --- a/configure +++ b/configure @@ -26384,110 +26384,6 @@ printf "%s\n" "#define HAVE_STAT_TV_NSEC2 1" >>confdefs.h fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether year with century should be normalized for strftime" >&5 -printf %s "checking whether year with century should be normalized for strftime... " >&6; } -if test ${ac_cv_normalize_century+y} -then : - printf %s "(cached) " >&6 -else $as_nop - -if test "$cross_compiling" = yes -then : - ac_cv_normalize_century=yes -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int main(void) -{ - char year[5]; - struct tm date = { - .tm_year = -1801, - .tm_mon = 0, - .tm_mday = 1 - }; - if (strftime(year, sizeof(year), "%Y", &date) && !strcmp(year, "0099")) { - return 1; - } - return 0; -} - -_ACEOF -if ac_fn_c_try_run "$LINENO" -then : - ac_cv_normalize_century=yes -else $as_nop - ac_cv_normalize_century=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_normalize_century" >&5 -printf "%s\n" "$ac_cv_normalize_century" >&6; } -if test "$ac_cv_normalize_century" = yes -then - -printf "%s\n" "#define Py_NORMALIZE_CENTURY 1" >>confdefs.h - -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C99-specific strftime specifiers are supported" >&5 -printf %s "checking whether C99-specific strftime specifiers are supported... " >&6; } -if test ${ac_cv_strftime_c99_support+y} -then : - printf %s "(cached) " >&6 -else $as_nop - -if test "$cross_compiling" = yes -then : - ac_cv_strftime_c99_support=no -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int main(void) -{ - char full_date[11]; - struct tm date = { - .tm_year = 0, - .tm_mon = 0, - .tm_mday = 1 - }; - if (strftime(full_date, sizeof(full_date), "%F", &date) && !strcmp(full_date, "1900-01-01")) { - return 0; - } - return 1; -} - -_ACEOF -if ac_fn_c_try_run "$LINENO" -then : - ac_cv_strftime_c99_support=yes -else $as_nop - ac_cv_strftime_c99_support=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_strftime_c99_support" >&5 -printf "%s\n" "$ac_cv_strftime_c99_support" >&6; } -if test "$ac_cv_strftime_c99_support" = yes -then - -printf "%s\n" "#define Py_STRFTIME_C99_SUPPORT 1" >>confdefs.h - -fi - have_curses=no have_panel=no diff --git a/configure.ac b/configure.ac index ee034e5a9621df..7edc7caa0e3d4c 100644 --- a/configure.ac +++ b/configure.ac @@ -6644,62 +6644,6 @@ then [Define if you have struct stat.st_mtimensec]) fi -AC_CACHE_CHECK([whether year with century should be normalized for strftime], [ac_cv_normalize_century], [ -AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include -#include - -int main(void) -{ - char year[5]; - struct tm date = { - .tm_year = -1801, - .tm_mon = 0, - .tm_mday = 1 - }; - if (strftime(year, sizeof(year), "%Y", &date) && !strcmp(year, "0099")) { - return 1; - } - return 0; -} -]])], -[ac_cv_normalize_century=yes], -[ac_cv_normalize_century=no], -[ac_cv_normalize_century=yes])]) -if test "$ac_cv_normalize_century" = yes -then - AC_DEFINE([Py_NORMALIZE_CENTURY], [1], - [Define if year with century should be normalized for strftime.]) -fi - -AC_CACHE_CHECK([whether C99-specific strftime specifiers are supported], [ac_cv_strftime_c99_support], [ -AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include -#include - -int main(void) -{ - char full_date[11]; - struct tm date = { - .tm_year = 0, - .tm_mon = 0, - .tm_mday = 1 - }; - if (strftime(full_date, sizeof(full_date), "%F", &date) && !strcmp(full_date, "1900-01-01")) { - return 0; - } - return 1; -} -]])], -[ac_cv_strftime_c99_support=yes], -[ac_cv_strftime_c99_support=no], -[ac_cv_strftime_c99_support=no])]) -if test "$ac_cv_strftime_c99_support" = yes -then - AC_DEFINE([Py_STRFTIME_C99_SUPPORT], [1], - [Define if C99-specific strftime specifiers are supported.]) -fi - dnl check for ncursesw/ncurses and panelw/panel dnl NOTE: old curses is not detected. dnl have_curses=[no, yes] diff --git a/pyconfig.h.in b/pyconfig.h.in index 1ca83fd2f2ca1b..6edd4a5678484f 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1706,18 +1706,12 @@ /* Defined if _Complex C type is available. */ #undef Py_HAVE_C_COMPLEX -/* Define if year with century should be normalized for strftime. */ -#undef Py_NORMALIZE_CENTURY - /* Define if rl_startup_hook takes arguments */ #undef Py_RL_STARTUP_HOOK_TAKES_ARGS /* Define if you want to enable internal statistics gathering. */ #undef Py_STATS -/* Define if C99-specific strftime specifiers are supported. */ -#undef Py_STRFTIME_C99_SUPPORT - /* The version of SunOS/Solaris as reported by `uname -r' without the dot. */ #undef Py_SUNOS_VERSION From 26441f90997b6442d7a9325cc2987161a83b753c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 8 Apr 2025 15:14:42 +0300 Subject: [PATCH 2/2] Add static variables to ignored.tsv. --- Modules/_datetimemodule.c | 20 ++++++++++---------- Tools/c-analyzer/cpython/ignored.tsv | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index bef98d484c72c1..c808d36b791d59 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1761,36 +1761,36 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, inline static int normalize_century(void) { - static int _normalize_century = -1; - if (_normalize_century < 0) { + static int cache = -1; + if (cache < 0) { char year[5]; struct tm date = { .tm_year = -1801, .tm_mon = 0, .tm_mday = 1 }; - _normalize_century = (strftime(year, sizeof(year), "%Y", &date) && - strcmp(year, "0099") != 0); + cache = (strftime(year, sizeof(year), "%Y", &date) && + strcmp(year, "0099") != 0); } - return _normalize_century; + return cache; } /* Check whether C99-specific strftime specifiers are supported. */ inline static int strftime_c99_support(void) { - static int _strftime_c99_support = -1; - if (_strftime_c99_support < 0) { + static int cache = -1; + if (cache < 0) { char full_date[11]; struct tm date = { .tm_year = 0, .tm_mon = 0, .tm_mday = 1 }; - _strftime_c99_support = (strftime(full_date, sizeof(full_date), "%F", &date) && - strcmp(full_date, "1900-01-01") == 0); + cache = (strftime(full_date, sizeof(full_date), "%F", &date) && + strcmp(full_date, "1900-01-01") == 0); } - return _strftime_c99_support; + return cache; } static PyObject * diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 14dc5007b65861..28a83c8c41fe45 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -224,6 +224,8 @@ Modules/_datetimemodule.c datetime_isoformat specs - Modules/_datetimemodule.c parse_hh_mm_ss_ff correction - Modules/_datetimemodule.c time_isoformat specs - Modules/_datetimemodule.c - capi_types - +Modules/_datetimemodule.c normalize_century cache - +Modules/_datetimemodule.c strftime_c99_support cache - Modules/_decimal/_decimal.c - cond_map_template - Modules/_decimal/_decimal.c - dec_signal_string - Modules/_decimal/_decimal.c - dflt_ctx - pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy