[lttng-dev] [PATCH babeltrace] Fix: Replace bt_timegm with a thread-safe implementation

Michael Jeanson mjeanson at efficios.com
Mon Nov 13 20:17:47 UTC 2017


The current compat wrapper for timegm is not thread-safe, it modifies
the process wide time settings with tzset. This was not a problem in bt1
as it was only used in the cli binary but it is now used in the trimmer
plugin which is used by the library.

Replace the wrapper with a basic implementation and add more tests.

Signed-off-by: Michael Jeanson <mjeanson at efficios.com>
---
 include/babeltrace/compat/utc-internal.h |  76 +++++++++-------
 tests/cli/test_trimmer.in                | 145 ++++++++++++++++++++++++++++---
 2 files changed, 177 insertions(+), 44 deletions(-)

diff --git a/include/babeltrace/compat/utc-internal.h b/include/babeltrace/compat/utc-internal.h
index db3035a..da19db8 100644
--- a/include/babeltrace/compat/utc-internal.h
+++ b/include/babeltrace/compat/utc-internal.h
@@ -44,50 +44,60 @@ time_t bt_timegm(struct tm *tm)
 
 #else
 
-#include <string.h>
-#include <stdlib.h>
-#include <glib.h>
+#include <errno.h>
 
 /*
- * Note: Below implementation of timegm() is not thread safe
- * as it changes the environment
- * variable TZ. It is OK as long as it is kept in self-contained program,
- * but should not be used within thread-safe library code.
+ * This is a simple implementation of timegm() it just turns the "struct tm" into
+ * a GMT time_t. It does not normalize any of the fields of the "struct tm", nor
+ * does it set tm_wday or tm_yday.
  */
 
 static inline
+int bt_leapyear(int year)
+{
+    return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0));
+}
+
+static inline
 time_t bt_timegm(struct tm *tm)
 {
-	time_t ret;
-	char *tz;
-
-	tz = getenv("TZ");
-	/*
-	 * Make a temporary copy, as the environment variable will be
-	 * modified.
-	 */
-	if (tz) {
-		tz = strdup(tz);
-		if (!tz) {
-			/*
-			 * Memory allocation error.
-			 */
-			return (time_t) -1;
+	int year, month, total_days;
+
+	int monthlen[2][12] = {
+		/* Days per month for a regular year */
+		{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+		/* Days per month for a leap year */
+		{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+	};
+
+	if ((tm->tm_mon >= 12) ||
+	    (tm->tm_mday >= 32) ||
+	    (tm->tm_hour >= 24) ||
+	    (tm->tm_min >= 60) ||
+	    (tm->tm_sec >= 61)) {
+		errno = EOVERFLOW;
+		return (time_t) -1;
+	}
+
+	/* Add 365 days for each year since 1970 */
+	total_days = 365 * (tm->tm_year - 70);
+
+	/* Add one day for each leap year since 1970 */
+	for (year = 70; year < tm->tm_year; year++) {
+		if (bt_leapyear(1900 + year)) {
+			total_days++;
 		}
 	}
 
-	/* Temporarily setting TZ to 1 for UTC */
-	g_setenv("TZ", "", 1);
-	tzset();
-	ret = mktime(tm);
-	if (tz) {
-		g_setenv("TZ", tz, 1);
-		free(tz);
-	} else {
-		unsetenv("TZ");
+	/* Add days for each remaining month */
+	for (month = 0; month < tm->tm_mon; month++) {
+		total_days += monthlen[bt_leapyear(1900 + year)][month];
 	}
-	tzset();
-	return ret;
+
+	/* Add remaining days */
+	total_days += tm->tm_mday - 1;
+
+	return ((((total_days * 24) + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec);
 }
 
 #endif
diff --git a/tests/cli/test_trimmer.in b/tests/cli/test_trimmer.in
index e69d7e0..249fffa 100644
--- a/tests/cli/test_trimmer.in
+++ b/tests/cli/test_trimmer.in
@@ -19,7 +19,7 @@
 
 TRACE_PATH="${BT_CTF_TRACES}/succeed/wk-heartbeat-u/"
 
-NUM_TESTS=10
+NUM_TESTS=44
 
 plan_tests $NUM_TESTS
 
@@ -27,40 +27,163 @@ tmp_out=$(mktemp)
 
 "${BT_BIN}" --clock-gmt --begin 17:48:17.587029529 --end 17:48:17.588680018 \
 	"${TRACE_PATH}" >/dev/null 2>&1
-ok $? "Read the trace with the trimmer enabled"
+ok $? "Read a trace with the trimmer enabled (GMT relative timestamps)"
 
 "${BT_BIN}" --clock-gmt --begin 17:48:17.587029529 "${TRACE_PATH}" \
 	2>/dev/null >"${tmp_out}"
-ok $? "Running with --begin"
+ok $? "Ran successfully with --begin (GMT relative timestamps)"
 cnt=$(wc -l < "${tmp_out}")
 test $cnt == 18
-ok $? "Expected number of events after trimming begin and end"
+ok $? "Received ${cnt}/18 events (GMT relative timestamps)"
 
 "${BT_BIN}" --clock-gmt --end 17:48:17.588680018 "${TRACE_PATH}" \
 	2>/dev/null >"${tmp_out}"
-ok $? "Running with --end"
+ok $? "Ran successfully with --end (GMT relative timestamps)"
 cnt=$(wc -l < "${tmp_out}")
 test $cnt == 9
-ok $? "Expected number of events after trimming end"
+ok $? "Received ${cnt}/9 events (GMT relative timestamps)"
 
 "${BT_BIN}" --clock-gmt --begin 17:48:17.587029529 --end 17:48:17.588680018 \
 	"${TRACE_PATH}" 2>/dev/null >"${tmp_out}"
-ok $? "Running with --begin and --end"
+ok $? "Ran successfully with --begin and --end (GMT relative timestamps)"
 cnt=$(wc -l < "${tmp_out}")
 test $cnt == 7
-ok $? "Expected number of events after trimming begin and end"
+ok $? "Received ${cnt}/7 events (GMT relative timestamps)"
 
 "${BT_BIN}" --clock-gmt --begin 18:48:17.587029529 "${TRACE_PATH}" \
 	2>/dev/null >"${tmp_out}"
-ok $? "Running with --begin out of range"
+ok $? "Ran successfully with --begin out of range (GMT relative timestamps)"
 cnt=$(wc -l < "${tmp_out}")
 test $cnt == 0
-ok $? "No event output when begin is after the end of the trace"
+ok $? "No events when begin is out of range (GMT relative timestamps)"
 
 "${BT_BIN}" --clock-gmt --end 16:48:17.588680018 "${TRACE_PATH}" \
 	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --end out of range (GMT relative timestamps)"
 cnt=$(wc -l < "${tmp_out}")
 test $cnt == 0
-ok $? "No event output when end is before the beginning of the trace"
+ok $? "No events when end is out of range (GMT relative timestamps)"
+
+
+"${BT_BIN}" --clock-gmt --begin "2012-10-29 17:48:17.587029529" --end "2012-10-29 17:48:17.588680018" \
+	"${TRACE_PATH}" >/dev/null 2>&1
+ok $? "Read a trace with the trimmer enabled (GMT absolute timestamps)"
+
+"${BT_BIN}" --clock-gmt --begin "2012-10-29 17:48:17.587029529" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin (GMT absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 18
+ok $? "Received ${cnt}/18 events (GMT absolute timestamps)"
+
+"${BT_BIN}" --clock-gmt --end "2012-10-29 17:48:17.588680018" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --end (GMT absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 9
+ok $? "Received ${cnt}/9 events (GMT absolute timestamps)"
+
+"${BT_BIN}" --clock-gmt --begin "2012-10-29 17:48:17.587029529" --end "2012-10-29 17:48:17.588680018" \
+	"${TRACE_PATH}" 2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin and --end (GMT absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 7
+ok $? "Received ${cnt}/7 events (GMT absolute timestamps)"
+
+"${BT_BIN}" --clock-gmt --begin "2012-10-29 18:48:17.587029529" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin out of range (GMT absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 0
+ok $? "No events when begin is out of range (GMT absolute timestamps)"
+
+"${BT_BIN}" --clock-gmt --end "2012-10-29 16:48:17.588680018" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --end out of range (GMT absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 0
+ok $? "No events when end is out of range (GMT absolute timestamps)"
+
+
+export TZ=EST
+
+"${BT_BIN}" --begin "12:48:17.587029529" --end "12:48:17.588680018" \
+	"${TRACE_PATH}" >/dev/null 2>&1
+ok $? "Read a trace with the trimmer enabled (EST relative timestamps)"
+
+"${BT_BIN}" --begin "12:48:17.587029529" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin (EST relative timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 18
+ok $? "Received ${cnt}/18 events (EST relative timestamps)"
+
+"${BT_BIN}" --end "12:48:17.588680018" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --end (EST relative timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 9
+ok $? "Received ${cnt}/9 events (EST relative timestamps)"
+
+"${BT_BIN}" --begin "12:48:17.587029529" --end "12:48:17.588680018" \
+	"${TRACE_PATH}" 2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin and --end (EST relative timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 7
+ok $? "Received ${cnt}/7 events (EST relative timestamps)"
+
+"${BT_BIN}" --begin "13:48:17.587029529" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin out of range (EST relative timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 0
+ok $? "No events when begin is out of range (EST relative timestamps)"
+
+"${BT_BIN}" --end "11:48:17.588680018" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --end out of range (EST relative timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 0
+ok $? "No events when end is out of range (EST relative timestamps)"
+
+
+"${BT_BIN}" --begin "2012-10-29 12:48:17.587029529" --end "2012-10-29 12:48:17.588680018" \
+	"${TRACE_PATH}" >/dev/null 2>&1
+ok $? "Read a trace with the trimmer enabled (EST absolute timestamps)"
+
+"${BT_BIN}" --begin "2012-10-29 12:48:17.587029529" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin (EST absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 18
+ok $? "Received ${cnt}/18 events (EST absolute timestamps)"
+
+"${BT_BIN}" --end "2012-10-29 12:48:17.588680018" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --end (EST absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 9
+ok $? "Received ${cnt}/9 events (EST absolute timestamps)"
+
+"${BT_BIN}" --begin "2012-10-29 12:48:17.587029529" --end "2012-10-29 12:48:17.588680018" \
+	"${TRACE_PATH}" 2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin and --end (EST absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 7
+ok $? "Received ${cnt}/7 events (EST absolute timestamps)"
+
+"${BT_BIN}" --begin "2012-10-29 13:48:17.587029529" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --begin out of range (EST absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 0
+ok $? "No events when begin is out of range (EST absolute timestamps)"
+
+"${BT_BIN}" --end "2012-10-29 11:48:17.588680018" "${TRACE_PATH}" \
+	2>/dev/null >"${tmp_out}"
+ok $? "Ran successfully with --end out of range (EST absolute timestamps)"
+cnt=$(wc -l < "${tmp_out}")
+test $cnt == 0
+ok $? "No events when end is out of range (EST absolute timestamps)"
 
 rm "${tmp_out}"
-- 
2.7.4



More information about the lttng-dev mailing list