Skip to content

Commit

Permalink
Removing MSVC C4996 from pragma block at the top of pybind11.h (#3129)
Browse files Browse the repository at this point in the history
* Removing MSVC C4996 from pragma block at the top of pybind11.h

* localtime_thread_safe, PYBIND11_COMPAT_STRDUP

* Adding #include <ctime> (attempt to fix MSVC 2015, 2017 errors).
  • Loading branch information
Ralf W. Grosse-Kunstleve authored Jul 26, 2021
1 parent e58c689 commit ff97f10
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 15 deletions.
33 changes: 24 additions & 9 deletions include/pybind11/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@
#pragma once

#include "pybind11.h"

#include <chrono>
#include <cmath>
#include <ctime>
#include <chrono>
#include <mutex>

#include <time.h>

#include <datetime.h>

// Backport the PyDateTime_DELTA functions from Python3.3 if required
Expand Down Expand Up @@ -95,6 +100,22 @@ template <typename type> class duration_caster {
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
};

inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) {
#if defined(__STDC_WANT_LIB_EXT1__) || defined(_MSC_VER)
if (localtime_s(buf, time))
return nullptr;
return buf;
#else
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
std::tm *tm_ptr = localtime(time);
if (tm_ptr != nullptr) {
*buf = *tm_ptr;
}
return tm_ptr;
#endif
}

// This is for casting times on the system clock into datetime.datetime instances
template <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
public:
Expand Down Expand Up @@ -162,16 +183,10 @@ template <typename Duration> class type_caster<std::chrono::time_point<std::chro
// (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
std::time_t tt = system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));

// std::localtime returns a pointer to a static internal std::tm object on success,
// or null pointer otherwise
std::tm *localtime_ptr = std::localtime(&tt);
std::tm localtime;
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
if (!localtime_ptr)
throw cast_error("Unable to represent system_clock in local time");

// this function uses static memory so it's best to copy it out asap just in case
// otherwise other code that is using localtime may break this (not just python code)
std::tm localtime = *localtime_ptr;

return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
localtime.tm_mon + 1,
localtime.tm_mday,
Expand Down
5 changes: 5 additions & 0 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@
# endif
#endif

// https://en.cppreference.com/w/c/chrono/localtime
#if defined(__STDC_LIB_EXT1__) && !defined(__STDC_WANT_LIB_EXT1__)
# define __STDC_WANT_LIB_EXT1__
#endif

#include <Python.h>
#include <frameobject.h>
#include <pythread.h>
Expand Down
19 changes: 13 additions & 6 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
# pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified
# pragma warning(disable: 4505) // warning C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only)
#elif defined(__GNUG__) && !defined(__clang__)
Expand All @@ -43,6 +42,8 @@
#include <string>
#include <utility>

#include <string.h>

#if defined(__cpp_lib_launder) && !(defined(_MSC_VER) && (_MSC_VER < 1914))
# define PYBIND11_STD_LAUNDER std::launder
# define PYBIND11_HAS_STD_LAUNDER 1
Expand Down Expand Up @@ -76,8 +77,13 @@ inline bool apply_exception_translators(std::forward_list<ExceptionTranslator>&
return false;
}

PYBIND11_NAMESPACE_END(detail)
#if defined(_MSC_VER)
# define PYBIND11_COMPAT_STRDUP _strdup
#else
# define PYBIND11_COMPAT_STRDUP strdup
#endif

PYBIND11_NAMESPACE_END(detail)

/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
class cpp_function : public function {
Expand Down Expand Up @@ -276,7 +282,7 @@ class cpp_function : public function {
std::free(s);
}
char *operator()(const char *s) {
auto t = strdup(s);
auto t = PYBIND11_COMPAT_STRDUP(s);
strings.push_back(t);
return t;
}
Expand Down Expand Up @@ -520,7 +526,8 @@ class cpp_function : public function {
auto *func = (PyCFunctionObject *) m_ptr;
std::free(const_cast<char *>(func->m_ml->ml_doc));
// Install docstring if it's non-empty (when at least one option is enabled)
func->m_ml->ml_doc = signatures.empty() ? nullptr : strdup(signatures.c_str());
func->m_ml->ml_doc
= signatures.empty() ? nullptr : PYBIND11_COMPAT_STRDUP(signatures.c_str());

if (rec->is_method) {
m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr());
Expand Down Expand Up @@ -1525,15 +1532,15 @@ class class_ : public detail::generic_type {
detail::process_attributes<Extra...>::init(extra..., rec_fget);
if (rec_fget->doc && rec_fget->doc != doc_prev) {
free(doc_prev);
rec_fget->doc = strdup(rec_fget->doc);
rec_fget->doc = PYBIND11_COMPAT_STRDUP(rec_fget->doc);
}
}
if (rec_fset) {
char *doc_prev = rec_fset->doc;
detail::process_attributes<Extra...>::init(extra..., rec_fset);
if (rec_fset->doc && rec_fset->doc != doc_prev) {
free(doc_prev);
rec_fset->doc = strdup(rec_fset->doc);
rec_fset->doc = PYBIND11_COMPAT_STRDUP(rec_fset->doc);
}
if (! rec_active) rec_active = rec_fset;
}
Expand Down

0 comments on commit ff97f10

Please sign in to comment.