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]

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


Hi,

On Sat, 2008-05-17 at 04:20 +0200, Mark Wielaard wrote:
> 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.

After testing on a 32bit system and after comments from Frank I changed
two things. I cap the value now to what would fit in a time_t on 32bit
systems (the calculations were already using native long values). And I
shouldn't have changed the MAX_STRINGLENGTH in lcpy and snprintf to 25,
that was too smart. The user should be able to override this.

Pushed as follows:

tapset/ChangeLog
2008-05-19  Mark Wielaard  <mwielaard@redhat.com>

    PR6524
    * ctime.stp: Don't try to convert values that won't fit in 32bits.

testsuite/ChangeLog
2008-05-19  Mark Wielaard  <mwielaard@redhat.com>

    PR 6524
    * systemtap.base/ctime.stp: New test.
    * systemtap.base/ctime.exp: New expect file.

Cheers,

Mark
diff --git a/tapset/ctime.stp b/tapset/ctime.stp
index cd8e502..96af4d4 100644
--- a/tapset/ctime.stp
+++ b/tapset/ctime.stp
@@ -4,7 +4,23 @@
  * 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 what can be represented
+ * with a 32 bit offset in seconds from the epoch) the returned string
+ * will be "a long, long time ago...". If the time would be
+ * unreasonable far in the future 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 earliest full date given by ctime, corresponding to epochsecs
+ * -2147483648 is "Fri Dec 13 20:45:52 1901". The latest full date
+ * given by ctime, corresponding to epachsecs 2147483647 is
+ * "Tue Jan 19 03:14:07 2038".
  *
  * The abbreviations for the days of the week are âSunâ, âMonâ, âTueâ,
  * âWedâ, âThuâ, âFriâ, and âSatâ.  The abbreviations for the months
@@ -21,7 +37,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 +86,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 what can be represented normally on a 32bit machine.
+    int64_t MAX_POS_SECS =  2147483647LL;
+    int64_t MIN_NEG_SECS = -2147483648LL;
+
+    if (THIS->epochsecs > MAX_POS_SECS)
+      {
+        strlcpy(THIS->__retvalue, "far far in the future...", MAXSTRINGLEN);
+	return;
+      }
+    if (THIS->epochsecs < MIN_NEG_SECS)
+      {
+        strlcpy(THIS->__retvalue, "a long, long time ago...", MAXSTRINGLEN);
+        return;
+      }
+
     lcltime = THIS->epochsecs;
    
     days = ((long)lcltime) / SECSPERDAY;
diff --git a/testsuite/systemtap.base/ctime.exp b/testsuite/systemtap.base/ctime.exp
new file mode 100644
index 0000000..f6db096
--- /dev/null
+++ b/testsuite/systemtap.base/ctime.exp
@@ -0,0 +1,18 @@
+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
+Sat Mar  3 09:46:40 1973
+Fri Feb 13 23:31:30 2009
+Sat Jan 10 13:37:04 2004
+Fri Jul 13 11:01:20 2012
+a long, long time ago...
+far far in the future...
+Fri Dec 13 20:45:52 1901
+a long, long time ago...
+Tue Jan 19 03:14:07 2038
+far far in the future...
+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..680baff
--- /dev/null
+++ b/testsuite/systemtap.base/ctime.stp
@@ -0,0 +1,55 @@
+probe begin 
+{
+	// epoch
+	println(ctime(0))
+
+	// epoch - 1
+	println(ctime(-1))
+
+	// epoch + 1
+	println(ctime(1))
+
+	// Some funny numbers
+	println(ctime(100000000))
+	println(ctime(1234567890))
+	println(ctime(1073741824))
+	println(ctime(0x50000000))
+
+	// some time really long ago
+	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))
+
+	// some time in the far future
+	time = (9999 - epoch_year) * 365 * secsperday
+	println(ctime(time))
+
+	// min 32 bit
+	time = -2147483648
+	println(ctime(time))
+
+	// over the edge, a long, long time ago...
+	time--
+	println(ctime(time))
+
+	// max 32 bit
+	time = 2147483647
+	println(ctime(time))
+
+	// over the edge, far far in the future...
+	time++
+	println(ctime(time))
+
+	// 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]