Package: thttpd
Version: 2.21b-11
Tags: patch
To reproduce the bug:
1) start thttpd daemon (start-up options don't matter);
2) set the system clock 10 minutes back;
3) do nothing for about 6 minutes;
4) thttpd will terminate without a log message.
The bug appears in early versions as well:
http://www.mail-archive.com/php-gene...@lists.php.net/msg174036.html
Reasons.
The software utilizes system time to implement a number of internal
timers for:
- internal watchdog;
- periodic file mmap cache expiration check;
- periodic idle connections closing;
- periodic average rate updates for throttles;
- periodic statistics displaying;
- connections "wake-up" (recovery);
- lingering connections closing;
- CGI execution time limit implementation (CGI_TIMELIMIT).
So the problem is a scheduled time is no longer valid after system time
changing. For example, current time is 15:00 and thttpd schedules some
timer to expire in 5 minutes i.e. at 15:05, then system time changes
(DST, manual adjusting by user / NTP cron script). As a result, one of
the following happens:
1) all active timers expire too late, if system time went backwards;
2) all active timers expire too early (even immediately), if system time
went forward.
In the first case, if a watchdog handler is not called within
appropriate period, the program calls abort() (thttpd.c:handle_alrm())
to go out of hang state (as it's supposed to happen). Other negative
consequences (normal operation interruption) are also possible.
Solution.
The patch attached checks for MONOTONIC clock availability and uses it
for timers expiration evaluation instead of system time. This includes
both compile-time check (for the clock access function availability) and
run-time check (to ensure that monotonic clock time is fetchable).
Notes: an ideal solution should completely re-write thttpd to POSIX timers.
Best regards,
Mikhail Zolotaryov
diff -Nru thttpd-2.25b.orig/configure thttpd-2.25b/configure
--- thttpd-2.25b.orig/configure 2003-12-25 20:44:33.0 +0200
+++ thttpd-2.25b/configure 2010-07-08 00:07:24.0 +0300
@@ -2299,13 +2299,61 @@
;;
esac
+echo $ac_n "checking for clock_gettime in -lrt""... $ac_c" 1>&6
+echo "configure:2304: checking for clock_gettime in -lrt" >&5
+ac_lib_var=`echo rt'_'clock_gettime | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lrt $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } &&
test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ac_tr_lib=HAVE_LIB`echo rt | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <&6
+fi
+
+
echo $ac_n "checking if struct tm has tm_gmtoff member""... $ac_c" 1>&6
-echo "configure:2304: checking if struct tm has tm_gmtoff member" >&5
+echo "configure:2352: checking if struct tm has tm_gmtoff member" >&5
if eval "test \"`echo '$''{'ac_cv_acme_tm_has_tm_gmtoff'+set}'`\" = set";
then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
@@ -2314,7 +2362,7 @@
u_int i = sizeof(((struct tm *)0)->tm_gmtoff)
; return 0; }
EOF
-if { (eval echo configure:2318: \"$ac_compile\") 1>&5; (eval $ac_compile)
2>&5; }; then
+if { (eval echo configure:2366: \"$ac_compile\") 1>&5; (eval $ac_compile)
2>&5; }; then
rm -rf conftest*
ac_cv_acme_tm_has_tm_gmtoff=yes
else
@@ -2334,12 +2382,12 @@
fi
echo $ac_n "checking if int64_t exists""... $ac_c" 1>&6
-echo "configure:2338: checking if int64_t exists" >&5
+echo "configure:2386: checking if int64_t exists" >&5
if eval "test \"`echo '$''{'ac_cv_acme_int64_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
@@ -2347,7 +2395,7 @@
int64_t i64
; return 0; }
EOF
-if { (eval echo configure:2351: \"$ac_compile\") 1>&5; (eval $ac_compile)
2>&5; }; then
+if { (eval echo configure:2399: \"$ac_compile\") 1>&5; (eval $ac_compile)
2>&5; }; then
rm -rf conftest*
ac_cv_acme_int64_t=yes
else
@@ -2367,12 +2415,12 @@
fi
echo $ac_n "checking if socklen_t exists""... $ac_c" 1>&6
-echo "configure:2371: checking if socklen_t exists" >&5
+echo "configure:2419: checking if socklen_t exists" >&5
if eval "test \"`echo '$''{'ac_cv_acme_socklen_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
@@ -2381,7 +2429,7 @@
socklen_t slen
; return 0; }
EOF
-if { (eval echo configure:2385: \"$ac_compile\") 1>&5; (eval $ac_compile)
2>&5; }; then
+if { (eval echo configure:2433: \"$ac_compile\") 1>&5; (eval $ac_c