chris@mimsy.UUCP (Chris Torek) (03/09/88)
Index: /usr/src/usr.lib/sendmail/src/usersmtp.c 4.3BSD Fix
Description:
When processing long mailing lists, sendmail sometimes
aborts with a `longjmp botch'.
Repeat-by:
Difficult.
Fix:
The problem occurs when sendmail has a read timeout of more
than five minutes specified in the configuration file. In
usersmtp.c, sendmail sets up a timeout event around the
`greeting' reply call; this timeout is scheduled to occur in
300 seconds (5 minutes). It then calls reply(), which calls
sfgets(), which notes that ReadTimeout is (e.g.) 1 hour.
sfgets sets another timeout event for one hour, reads a line,
clears the timeout event, and returns to usersmtp, which clears
its own read timeout.
Suppose, however, that no reply is made within the first five
minutes. Then the first event, usersmtp.c's timeout, fires
off. This does a longjmp() all the way out of sfgets and reply
back to usersmtp.c, which then returns to its caller, leaving
in the event queue the event posted by sfgets. In one hour, if
sendmail is still running by then, this event attempts to
longjmp back to the context set by the sfgets from reply. This
context is long gone and, with any luck, longjmp notices and
aborts.
There are several ways to fix this. The most general would be
for sendmail to have a `wrapper' around setjmp and longjmp that
would provide unwind protection. That is beyond the scope of
this message.
The second way is simply to remove the 5 minute timeout from
usersmtp.c. Commenting out the setevent() call should
suffice. This is somewhat undesirable but is by far the
easiest fix.
The third way is to have usersmtp.c arrange for ReadTimeout to
be set to 300, preserving its old value and restoring it after
the first call to reply. The following UNTESTED change does
this.
Chris
*** usersmtp.c.old Wed Mar 9 06:08:59 1988
--- usersmtp.c Wed Mar 9 06:10:53 1988
***************
*** 67,72 ****
*/
- jmp_buf CtxGreeting;
-
smtpinit(m, pvp)
struct mailer *m;
--- 67,70 ----
***************
*** 76,80 ****
EVENT *gte;
char buf[MAXNAME];
! extern greettimeout();
/*
--- 74,78 ----
EVENT *gte;
char buf[MAXNAME];
! int oldtimeout;
/*
***************
*** 129,138 ****
*/
! if (setjmp(CtxGreeting) != 0)
! goto tempfail;
! gte = setevent((time_t) 300, greettimeout, 0);
SmtpPhase = "greeting wait";
r = reply(m);
! clrevent(gte);
if (r < 0 || REPLYTYPE(r) != 2)
goto tempfail;
--- 127,135 ----
*/
! oldtimeout = ReadTimeout;
! ReadTimeout = 5 * 60;
SmtpPhase = "greeting wait";
r = reply(m);
! ReadTimeout = oldtimeout;
if (r < 0 || REPLYTYPE(r) != 2)
goto tempfail;
***************
*** 213,223 ****
}
-
- static
- greettimeout()
- {
- /* timeout reading the greeting message */
- longjmp(CtxGreeting, 1);
- }
/*
** SMTPRCPT -- designate recipient.
--- 210,213 ----
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
jis@BITSY.MIT.EDU (Jeffrey I. Schiller) (03/13/88)
Posting-Front-End: Gnews 1.0
Chris's change should work. We ran into this problem awhile ago here
(with the "expert" mailing list). I thought we posted the fix (but I guess not).
In any event here are the diffs (against the version of sendmail we were using
then). This code has been in service at MIT since November of 1986.
-Jeff
*** /tmp/,RCSt1005512 Sat Mar 12 21:22:30 1988
--- /tmp/,RCSt2005512 Sat Mar 12 21:22:37 1988
***************
*** 1,4 ****
--- 1,9 ----
/*
+ * $Source: /source/4.3/usr.lib/sendmail/src/RCS/usersmtp.c,v $
+ * $Header: usersmtp.c,v 1.2 86/11/04 00:36:34 jis Exp $
+ */
+
+ /*
** Sendmail
** Copyright (c) 1983 Eric P. Allman
** Berkeley, California
***************
*** 67,74 ****
** creates connection and sends initial protocol.
*/
- jmp_buf CtxGreeting;
-
smtpinit(m, pvp)
struct mailer *m;
char **pvp;
--- 72,77 ----
***************
*** 76,81 ****
--- 79,85 ----
register int r;
EVENT *gte;
char buf[MAXNAME];
+ time_t saveReadTimeout;
extern greettimeout();
/*
***************
*** 127,140 ****
** Get the greeting message.
** This should appear spontaneously. Give it five minutes to
** happen.
*/
- if (setjmp(CtxGreeting) != 0)
- goto tempfail;
- gte = setevent((time_t) 300, greettimeout, 0);
SmtpPhase = "greeting wait";
r = reply(m);
! clrevent(gte);
if (r < 0 || REPLYTYPE(r) != 2)
goto tempfail;
--- 131,160 ----
** Get the greeting message.
** This should appear spontaneously. Give it five minutes to
** happen.
+ **
+ ** JIS: We change the global variable ReadTimeout to be 5
+ ** minutes. This variable is used by the lowlevel routine
+ ** sfgets to determine how long to wait for input.
+ ** when we get our greeting we return ReadTimeout to its
+ ** previous state. IMPORTANT: The older code I replaced
+ ** used a separate timeout (via a setjmp and longjmp)
+ ** this LOSES REAL BIG if the 5 minute timeout goes off
+ ** for then sfgets gets its stack unwound and leaves
+ ** a lingering event that will eventually cause a longjmp
+ ** to some ancient stack history, sendmail then dies horribly.
+ ** This usually happens only when dealing with large mailing
+ ** lists ("xpert" in this case > 200 recipients), which is
+ ** the LAST place you want to dump core, for then the queue
+ ** files are out of date and LOTS of people get a duplicate
+ ** copy of the message that was in progress.
+ *
*/
SmtpPhase = "greeting wait";
+ saveReadTimeout = ReadTimeout;
+ ReadTimeout = 300;
r = reply(m);
! ReadTimeout = saveReadTimeout;
if (r < 0 || REPLYTYPE(r) != 2)
goto tempfail;
***************
*** 212,225 ****
unavailable:
smtpquit(m);
return (EX_UNAVAILABLE);
- }
-
-
- static
- greettimeout()
- {
- /* timeout reading the greeting message */
- longjmp(CtxGreeting, 1);
}
/*
** SMTPRCPT -- designate recipient.
--- 232,237 ----
---- End of Mesage ---
--