summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiza Sulistyo <riza@teluu.com>2016-10-13 04:32:29 +0000
committerRiza Sulistyo <riza@teluu.com>2016-10-13 04:32:29 +0000
commit4412f8cdfdab2c140f70e10e0932a30c5091373b (patch)
tree0eb2b2fc7b9d1bffe8a2ac031180e187e1be0666
parent94144542bbf37dd74b10865a4125ddaf9c119068 (diff)
Re #1945 (misc): Use localtime_r() instead of localtime() (if available) since localtime() is not thread safe.
This fixes a data race in pj_time_decode() which is called from multiple threads. Thanks to Kal (b17 c0de) for the patch. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5458 74dad513-b988-da41-8d7b-12977e46ad98
-rwxr-xr-xaconfigure6
-rw-r--r--aconfigure.ac3
-rw-r--r--pjlib/include/pj/compat/os_auto.h.in3
-rw-r--r--pjlib/include/pj/compat/os_darwinos.h2
-rw-r--r--pjlib/include/pj/compat/os_linux.h2
-rw-r--r--pjlib/src/pj/os_time_common.c25
6 files changed, 31 insertions, 10 deletions
diff --git a/aconfigure b/aconfigure
index 4aa28a50..db88162c 100755
--- a/aconfigure
+++ b/aconfigure
@@ -5414,6 +5414,12 @@ if test "x$ac_cv_header_net_if_h" = xyes; then :
fi
+ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
+if test "x$ac_cv_func_localtime_r" = xyes; then :
+ $as_echo "#define PJ_HAS_LOCALTIME_R 1" >>confdefs.h
+
+fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Setting PJ_OS_NAME to $target" >&5
$as_echo "Setting PJ_OS_NAME to $target" >&6; }
cat >>confdefs.h <<_ACEOF
diff --git a/aconfigure.ac b/aconfigure.ac
index df9e1ae2..387a37ce 100644
--- a/aconfigure.ac
+++ b/aconfigure.ac
@@ -265,6 +265,9 @@ AC_CHECK_HEADER(net/if.h,[AC_DEFINE(PJ_HAS_NET_IF_H,1)],[],
# include <sys/socket.h>
#endif
])
+
+AC_CHECK_FUNC(localtime_r,[AC_DEFINE(PJ_HAS_LOCALTIME_R,1)])
+
AC_MSG_RESULT([Setting PJ_OS_NAME to $target])
AC_DEFINE_UNQUOTED(PJ_OS_NAME,["$target"])
diff --git a/pjlib/include/pj/compat/os_auto.h.in b/pjlib/include/pj/compat/os_auto.h.in
index 7eb89562..70018ba6 100644
--- a/pjlib/include/pj/compat/os_auto.h.in
+++ b/pjlib/include/pj/compat/os_auto.h.in
@@ -166,6 +166,9 @@
# define PJ_OS_HAS_CHECK_STACK 0
#endif
+/* Is localtime_r() available? */
+#undef PJ_HAS_LOCALTIME_R
+
/* Unicode? */
#undef PJ_NATIVE_STRING_IS_UNICODE
diff --git a/pjlib/include/pj/compat/os_darwinos.h b/pjlib/include/pj/compat/os_darwinos.h
index 8cccd425..98435a8b 100644
--- a/pjlib/include/pj/compat/os_darwinos.h
+++ b/pjlib/include/pj/compat/os_darwinos.h
@@ -55,6 +55,8 @@
#define PJ_HAS_WINSOCK_H 0
#define PJ_HAS_WINSOCK2_H 0
+#define PJ_HAS_LOCALTIME_R 1
+
/* Is errno a good way to retrieve OS errors?
*/
#define PJ_HAS_ERRNO_VAR 1
diff --git a/pjlib/include/pj/compat/os_linux.h b/pjlib/include/pj/compat/os_linux.h
index 40840e25..c33f2c19 100644
--- a/pjlib/include/pj/compat/os_linux.h
+++ b/pjlib/include/pj/compat/os_linux.h
@@ -55,6 +55,8 @@
#define PJ_HAS_WINSOCK_H 0
#define PJ_HAS_WINSOCK2_H 0
+#define PJ_HAS_LOCALTIME_R 1
+
#define PJ_SOCK_HAS_INET_ATON 1
/* Set 1 if native sockaddr_in has sin_len member.
diff --git a/pjlib/src/pj/os_time_common.c b/pjlib/src/pj/os_time_common.c
index da4440d1..f14fa961 100644
--- a/pjlib/src/pj/os_time_common.c
+++ b/pjlib/src/pj/os_time_common.c
@@ -28,19 +28,24 @@
PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
{
- struct tm *local_time;
+ struct tm local_time;
PJ_CHECK_STACK();
- local_time = localtime((time_t*)&tv->sec);
-
- pt->year = local_time->tm_year+1900;
- pt->mon = local_time->tm_mon;
- pt->day = local_time->tm_mday;
- pt->hour = local_time->tm_hour;
- pt->min = local_time->tm_min;
- pt->sec = local_time->tm_sec;
- pt->wday = local_time->tm_wday;
+#if defined(PJ_HAS_LOCALTIME_R) && PJ_HAS_LOCALTIME_R != 0
+ localtime_r((time_t*)&tv->sec, &local_time);
+#else
+ /* localtime() is NOT thread-safe. */
+ local_time = *localtime((time_t*)&tv->sec);
+#endif
+
+ pt->year = local_time.tm_year+1900;
+ pt->mon = local_time.tm_mon;
+ pt->day = local_time.tm_mday;
+ pt->hour = local_time.tm_hour;
+ pt->min = local_time.tm_min;
+ pt->sec = local_time.tm_sec;
+ pt->wday = local_time.tm_wday;
pt->msec = tv->msec;
return PJ_SUCCESS;