This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] bug #6524 - ctime() on bad values hangs system


Hi,

While playing a bit with ctime I hit bug #6524. Since ctime() accepts a
64bit long the year/month/day computation could take ages when given a
bogus epoch offset. The following patch makes it so that the printed
string is capped to somewhat reasonable values, otherwise it just
returns "a long, long time ago...", or "far far in the future...". Care
is taken to make sure that the returned string is always 24 chars wide.
Also included is a new ctime test against some corner case values.

Let me know if this patch is ok, or can be improved.

Thanks

Mark
diff --git a/tapset/ctime.stp b/tapset/ctime.stp
index cd8e502..fb31d41 100644
--- a/tapset/ctime.stp
+++ b/tapset/ctime.stp
@@ -4,7 +4,18 @@
  * Takes an argument of seconds since the epoch as returned by
  * gettimeofday_s(). Returns a string of the form
  *
- *   "Wed Jun 30 21:49:008 1993"
+ *   "Wed Jun 30 21:49:08 1993"
+ *
+ * The string will always be exactly 24 characters. If the time would
+ * be unreasonable far in the past (before aprox. the year 1000) the
+ * returned string will be "a long, long time ago...". If the time would
+ * be unreasonable far in the future (after aprox. the year 9999) the
+ * returned string will be "far far in the future..."
+ * (both these strings are also 24 characters wide).
+ *
+ * Note that the epoch (zero) corresponds to
+ *
+ *   "Thu Jan  1 00:00:00 1970"
  *
  * The abbreviations for the days of the week are âSunâ, âMonâ, âTueâ,
  * âWedâ, âThuâ, âFriâ, and âSatâ.  The abbreviations for the months
@@ -21,7 +32,7 @@
  * tzcode maintained by Arthur David Olson.  In newlib, asctime_r.c
  * doesn't have any author/copyright information.
  *
- * Changes copyright (C) 2006 Red Hat Inc.
+ * Changes copyright (C) 2006, 2008 Red Hat Inc.
  */
 
 function ctime:string(epochsecs:long)
@@ -70,6 +81,25 @@ function ctime:string(epochsecs:long)
     int tm_year;        /* year */
     int tm_wday;        /* day of the week */
 
+    // Check that the numer of seconds is "reasonable".
+    // Otherwise (especially on 64bit machines) we will be spending
+    // way too much time calculating the correct year, month and
+    // day. Also we would like the returned string to always be 24 chars.
+    // So cap to aprox. 1000 till 9999 years, ignoring leap days.
+    static long MAX_POS_SECS = (9999L - EPOCH_YEAR) * 365L * SECSPERDAY;
+    static long MIN_NEG_SECS = -1L * (EPOCH_YEAR - 1000L) * 365L * SECSPERDAY;
+
+    if (THIS->epochsecs > MAX_POS_SECS)
+      {
+        strlcpy(THIS->__retvalue, "far far in the future...", 25);
+	return;
+      }
+    if (THIS->epochsecs < MIN_NEG_SECS)
+      {
+        strlcpy(THIS->__retvalue, "a long, long time ago...", 25);
+        return;
+      }
+
     lcltime = THIS->epochsecs;
    
     days = ((long)lcltime) / SECSPERDAY;
@@ -128,7 +158,7 @@ function ctime:string(epochsecs:long)
      * convert it to an ascii representation.
      */
 
-    snprintf (THIS->__retvalue, MAXSTRINGLEN, "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
+    snprintf (THIS->__retvalue, 25, "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
 	      day_name[tm_wday], mon_name[tm_mon],
 	      tm_mday, tm_hour, tm_min,
 	      tm_sec, tm_year);
diff --git a/testsuite/systemtap.base/ctime.exp b/testsuite/systemtap.base/ctime.exp
new file mode 100644
index 0000000..7fbebf5
--- /dev/null
+++ b/testsuite/systemtap.base/ctime.exp
@@ -0,0 +1,14 @@
+set test "ctime"
+set ::result_string {Thu Jan  1 00:00:00 1970
+Wed Dec 31 23:59:59 1969
+Thu Jan  1 00:00:01 1970
+Sun Aug 24 00:00:00 1000
+a long, long time ago...
+Thu Sep  2 00:00:00 9993
+far far in the future...
+Fri Dec 13 20:45:52 1901
+Tue Jan 19 03:14:07 2038
+a long, long time ago...
+far far in the future...
+}
+stap_run2 $srcdir/$subdir/$test.stp
diff --git a/testsuite/systemtap.base/ctime.stp b/testsuite/systemtap.base/ctime.stp
new file mode 100644
index 0000000..7c10785
--- /dev/null
+++ b/testsuite/systemtap.base/ctime.stp
@@ -0,0 +1,47 @@
+probe begin 
+{
+	// epoch
+	println(ctime(0))
+
+	// epoch - 1
+	println(ctime(-1))
+
+	// epoch + 1
+	println(ctime(1))
+
+	// a pretty long time ago, but not that far in the past
+	secspermin = 60
+	minsperhour = 60
+	hoursperday = 24
+	secsperhour = secspermin * minsperhour
+	secsperday = secsperhour * hoursperday
+	epoch_year = 1970
+	time = -1 * (epoch_year - 1000) * 365 * secsperday
+	println(ctime(time))
+
+	// over the edge, a long, long time ago...
+	time--
+	println(ctime(time))
+
+	// a pretty far time in the future, but not that far in the future
+	time = (9999 - epoch_year) * 365 * secsperday
+	println(ctime(time))
+
+	// over the edge, far far in the future...
+	time++
+	println(ctime(time))
+
+	// min 32 bit
+	println(ctime(-2147483648))
+
+	// max 32 bit
+	println(ctime(2147483647))
+
+	// min 64 bit
+	println(ctime(-9223372036854775808))
+
+	// max 64 bit
+	println(ctime(9223372036854775807))
+
+	exit()
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]