MB-19279: Fix race in use of gmtime() 80/63080/5
authorDave Rigby <daver@couchbase.com>
Wed, 12 Nov 2014 17:05:56 +0000 (17:05 +0000)
committerChiyoung Seo <chiyoung@couchbase.com>
Sat, 23 Apr 2016 01:16:16 +0000 (01:16 +0000)
As identified by ThreadSanitizer:

    WARNING: ThreadSanitizer: data race (pid=17259)
      Write of size 8 at 0x7fec86e44de0 by main thread (mutexes: write M1161):
#0 gmtime ??:0 (libtsan.so.0+0x000000025135)
#1 EventuallyPersistentEngine::doEngineStats(void const*, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /repos/couchbase/server/source/ep-engine/src/ep_engine.cc:3369 (ep.so+0x00000010f4be)
#2 EventuallyPersistentEngine::getStats(void const*, char const*, int, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /repos/couchbase/server/source/ep-engine/src/ep_engine.cc:4339 (ep.so+0x000000113c35)
#3 EvpGetStats /repos/couchbase/server/source/ep-engine/src/ep_engine.cc:217 (ep.so+0x000000102b14)
#4 mock_get_stats /repos/couchbase/server/source/memcached/programs/engine_testapp/engine_testapp.c:195 (exe+0x0000000026de)
#5 get_int_stat(engine_interface*, engine_interface_v1*, char const*, char const*) /repos/couchbase/server/source/ep-engine/tests/ep_test_apis.cc:799 (ep_testsuite.so+0x0000000832d8)
#6 wait_for_stat_change(engine_interface*, engine_interface_v1*, char const*, int, char const*) /repos/couchbase/server/source/ep-engine/tests/ep_test_apis.cc:846 (ep_testsuite.so+0x0000000838d6)
#7 test_setup /repos/couchbase/server/source/ep-engine/tests/ep_testsuite.cc:178 (ep_testsuite.so+0x00000001ee69)
#8 execute_test /repos/couchbase/server/source/memcached/programs/engine_testapp/engine_testapp.c:1050 (exe+0x000000005970)
#9 main /repos/couchbase/server/source/memcached/programs/engine_testapp/engine_testapp.c:1313 (exe+0x000000006606)

      Previous write of size 8 at 0x7fec86e44de0 by thread T7:
#0 gmtime ??:0 (libtsan.so.0+0x000000025135)
#1 EventuallyPersistentEngine::doEngineStats(void const*, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /repos/couchbase/server/source/ep-engine/src/ep_engine.cc:3369 (ep.so+0x00000010f4be)
#2 EventuallyPersistentEngine::getStats(void const*, char const*, int, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /repos/couchbase/server/source/ep-engine/src/ep_engine.cc:4339 (ep.so+0x000000113c35)
#3 EventuallyPersistentStore::snapshotStats() /repos/couchbase/server/source/ep-engine/src/ep.cc:1465 (ep.so+0x0000000e150e)
#4 StatSnap::run() /repos/couchbase/server/source/ep-engine/src/tasks.cc:79 (ep.so+0x000000174db2)
#5 ExecutorThread::run() /repos/couchbase/server/source/ep-engine/src/executorthread.cc:110 (ep.so+0x00000014a0e7)
#6 launch_executor_thread /repos/couchbase/server/source/ep-engine/src/executorthread.cc:34 (ep.so+0x000000149930)
#7 platform_thread_wrap /repos/couchbase/server/source/platform/src/cb_pthreads.c:19 (libplatform.so.0.1.0+0x000000002d8b)
#8 __tsan_write_range ??:0 (libtsan.so.0+0x00000001b1c9)

Switch to gmtime_r which is thread-safe.

Change-Id: Id0773df65f4fc569c0a173b6185b1ef8bd91862d
Reviewed-on: http://review.couchbase.org/63080
Well-Formed: buildbot <build@couchbase.com>
Reviewed-by: Jim Walker <jim@couchbase.com>
Reviewed-by: Will Gardner <will.gardner@couchbase.com>
Tested-by: buildbot <build@couchbase.com>
src/ep_engine.cc

index d87d454..160e67e 100644 (file)
@@ -3368,10 +3368,15 @@ ENGINE_ERROR_CODE EventuallyPersistentEngine::doEngineStats(const void *cookie,
 
     if (getConfiguration().isAccessScannerEnabled()) {
         char timestr[20];
-        struct tm alogTim = *gmtime((time_t *)&epstats.alogTime);
-        strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &alogTim);
-        add_casted_stat("ep_access_scanner_task_time", timestr, add_stat,
-                        cookie);
+        struct tm alogTim;
+        if (gmtime_r((time_t *)&epstats.alogTime, &alogTim) == NULL) {
+            add_casted_stat("ep_access_scanner_task_time", "UNKNOWN", add_stat,
+                            cookie);
+        } else {
+            strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &alogTim);
+            add_casted_stat("ep_access_scanner_task_time", timestr, add_stat,
+                            cookie);
+        }
     } else {
         add_casted_stat("ep_access_scanner_task_time", "NOT_SCHEDULED",
                         add_stat, cookie);