summaryrefslogtreecommitdiff
path: root/src/test/builtin_timezones.c
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2020-10-21 22:36:45 +0200
committerAllen Winter <allen.winter@kdab.com>2021-01-09 09:15:10 -0500
commit903248f5e4d8e5ea0b23714535bdc9b174b571b4 (patch)
tree4b067976364855375a48b38bb828015abe076d64 /src/test/builtin_timezones.c
parent1a62ceb499f48f82eef538cff81bcd915695f07c (diff)
downloadlibical-git-903248f5e4d8e5ea0b23714535bdc9b174b571b4.tar.gz
Improve thread safety of icaltimezone_load_builtin_timezone()
Even the function does test whether the passed-in zone has set the component, it doesn't retest it when it acquires the lock, but other thread could already assign the component, which can cause use-after-free in certain thread interleaving. Signed-off-by: Allen Winter <allen.winter@kdab.com>
Diffstat (limited to 'src/test/builtin_timezones.c')
-rw-r--r--src/test/builtin_timezones.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/test/builtin_timezones.c b/src/test/builtin_timezones.c
index 5a24a52d..08f793d3 100644
--- a/src/test/builtin_timezones.c
+++ b/src/test/builtin_timezones.c
@@ -20,10 +20,63 @@
#include <config.h>
#endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#include <assert.h>
+#endif
+
#include "libical/ical.h"
#include <stdio.h>
+#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_CREATE)
+
+#define N_THREADS 20
+
+static pthread_mutex_t thread_comp_mutex = PTHREAD_MUTEX_INITIALIZER;
+static const void *thread_comp = NULL;
+
+static void *
+thread_func(void *user_data)
+{
+ icaltimezone *zone = user_data;
+ icalcomponent *icalcomp;
+
+ if(!zone)
+ return NULL;
+
+ icalcomp = icaltimezone_get_component(zone);
+ pthread_mutex_lock(&thread_comp_mutex);
+ if(!thread_comp)
+ thread_comp = icalcomp;
+ else
+ assert(thread_comp == icalcomp);
+ pthread_mutex_unlock(&thread_comp_mutex);
+ icalcomp = icalcomponent_new_clone(icalcomp);
+ icalcomponent_free(icalcomp);
+
+ return NULL;
+}
+
+static void
+test_get_component_threadsafety(void)
+{
+ pthread_t thread[N_THREADS];
+ icaltimezone *zone;
+ int ii;
+
+ zone = icaltimezone_get_builtin_timezone("Europe/London");
+
+ for(ii = 0; ii < N_THREADS; ii++) {
+ pthread_create(&thread[ii], NULL, thread_func, zone);
+ }
+
+ for(ii = 0; ii < N_THREADS; ii++) {
+ pthread_join(thread[ii], NULL);
+ }
+}
+#endif
+
int main()
{
icalarray *builtin_timezones;
@@ -34,6 +87,10 @@ int main()
set_zone_directory("../../zoneinfo");
icaltimezone_set_tzid_prefix("/softwarestudio.org/");
+ #if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_CREATE)
+ test_get_component_threadsafety();
+ #endif
+
tt = icaltime_current_time_with_zone(icaltimezone_get_builtin_timezone("America/New_York"));
tt.year = 2038;