NetBSD Problem Report #48444
From www@NetBSD.org Thu Dec 12 11:17:27 2013
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
(Client CN "mail.NetBSD.org", Issuer "Postmaster NetBSD.org" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id 9890EA63C4
for <gnats-bugs@gnats.NetBSD.org>; Thu, 12 Dec 2013 11:17:27 +0000 (UTC)
Message-Id: <20131212111725.9919AA642D@mollari.NetBSD.org>
Date: Thu, 12 Dec 2013 11:17:25 +0000 (UTC)
From: sdaoden@gmail.com
Reply-To: sdaoden@gmail.com
To: gnats-bugs@NetBSD.org
Subject: mail(1)/mailx(1): relaxation of memory pressure
X-Send-Pr-Version: www-1.0
>Number: 48444
>Category: bin
>Synopsis: mail(1)/mailx(1): relaxation of memory pressure
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Dec 12 11:20:00 +0000 2013
>Originator: Steffen
>Release: 6.99.24
>Organization:
>Environment:
-
>Description:
sreset() drops all the auto-reclaimed storage and thus cannot
be used when iterating over all messages in a mailbox, because
there may have been allocations in that storage somewhere before.
Because of this the BSD Mail codebase simply iterates over all messages that belong to a message-selection, allocating more and more memory.
Therefore introduce a temporary additional layer on top of that
which can be used by such code paths without resetting yet
existent allocations.
/* The purpose of relaxation is only that it is possible to reset the
* casters, *not* to give back memory to the system. We are presumably in
* an iteration over all messages of a mailbox, and it'd be quite
* counterproductive to give the system allocator a chance to waste time */
>How-To-Repeat:
Open a (MIME-enabled) mail(1) instance on a mailbox with many messages and enter a condition where many messages are processed in order, e.g., 'view *', or change a message status flag ('unre NUMBER') when the mailbox is editable and leave the mailbox, causing an updated version to be written.
>Fix:
diff -Napru nmail/cmd1.c nmail.relax/cmd1.c
--- nmail/cmd1.c 2013-12-09 13:16:52.000000000 +0100
+++ nmail.relax/cmd1.c 2013-12-09 19:09:03.000000000 +0100
@@ -124,13 +124,16 @@ headers(void *v)
flag = 0;
if (dot != get_message(n))
dot = mp;
+ srelax_on();
for (/*EMPTY*/; mp; mp = next_message(mp)) {
if (mp->m_flag & MDELETED)
continue;
if (flag++ >= size)
break;
printhead(get_msgnum(mp));
+ srelax();
}
+ srelax_off();
if (flag == 0) {
(void)printf("No more mail.\n");
return 1;
@@ -343,6 +346,7 @@ type1(int *msgvec, int doign, int mime_d
* exit code will never be seen.
*/
sig_check();
+ srelax_on();
oldsigpipe = sig_signal(SIGPIPE, cmd1_brokpipe);
if (setjmp(pipestop))
goto close_pipe;
@@ -365,8 +369,10 @@ type1(int *msgvec, int doign, int mime_d
args.mip = NULL;
#endif
(void)thread_recursion(mp, type1_core, &args);
+ srelax();
}
close_pipe:
+ srelax_off();
#ifdef MIME_SUPPORT
if (mip != NULL) {
struct sigaction osa;
@@ -549,6 +555,7 @@ top(void *v)
args.lineb = 1;
recursive = do_recursion();
msgCount = get_msgCount();
+ srelax_on();
for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
struct message *mp;
@@ -556,7 +563,9 @@ top(void *v)
dot = mp;
args.parent = recursive ? mp : NULL;
(void)thread_recursion(mp, top_core, &args);
+ srelax();
}
+ srelax_off();
return 0;
}
diff -Napru nmail/cmd2.c nmail.relax/cmd2.c
--- nmail/cmd2.c 2013-12-09 13:16:52.000000000 +0100
+++ nmail.relax/cmd2.c 2013-12-09 19:02:25.000000000 +0100
@@ -234,6 +234,7 @@ save1(char str[], int markmsg, const cha
warn(NULL);
return 1;
}
+ srelax_on();
for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
struct save1_core_args_s args;
struct message *mp;
@@ -245,9 +246,12 @@ save1(char str[], int markmsg, const cha
if (thread_recursion(mp, save1_core, &args)) {
warn("%s", fn);
(void)Fclose(obuf);
+ srelax_off();
return 1;
}
+ srelax();
}
+ srelax_off();
(void)fflush(obuf);
if (ferror(obuf))
warn("%s", fn);
@@ -690,6 +694,7 @@ detach1(void *v, int do_unnamed)
msgvec[1] = 0;
}
recursive = do_recursion();
+ srelax_on();
for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
struct detach1_core_args_s args;
struct message *mp;
@@ -700,7 +705,9 @@ detach1(void *v, int do_unnamed)
args.igtab = do_unnamed ? detachall : ignoreall;
args.dstdir = dstdir;
(void)thread_recursion(mp, detach1_core, &args);
+ srelax();
}
+ srelax_off();
return 0;
}
diff -Napru nmail/extern.h nmail.relax/extern.h
--- nmail/extern.h 2013-12-09 13:16:52.000000000 +0100
+++ nmail.relax/extern.h 2013-12-09 18:36:12.000000000 +0100
@@ -278,6 +278,9 @@ int sendmail(void *);
void * csalloc(size_t, size_t);
void * salloc(size_t);
void sreset(void);
+void srelax_on(void);
+void srelax_off(void);
+void srelax(void);
void spreserve(void);
/*
diff -Napru nmail/list.c nmail.relax/list.c
--- nmail/list.c 2013-12-09 13:16:52.000000000 +0100
+++ nmail.relax/list.c 2013-12-09 19:06:33.000000000 +0100
@@ -845,6 +845,7 @@ match_string(int *markarray, char *str,
return -1;
rval = 0;
+ srelax_on();
for (i = 1; i <= msgCount; i++) {
struct message *mp;
mp = get_message(i);
@@ -854,7 +855,9 @@ match_string(int *markarray, char *str,
if (rval)
markarray[i - 1] = 1;
rval = 0;
+ srelax();
}
+ srelax_off();
free_cmparg(cmparg); /* free any memory allocated by get_cmpfn() */
@@ -1325,9 +1328,13 @@ show_headers_and_exit(int flags)
(void)signal(SIGINT, SIG_IGN);
flags &= CMMASK;
+ srelax_on();
for (mp = get_message(1); mp; mp = next_message(mp))
- if (flags == 0 || !ignore_message(mp->m_flag, flags))
+ if (flags == 0 || !ignore_message(mp->m_flag, flags)) {
printhead(get_msgnum(mp));
+ srelax();
+ }
+ srelax_off();
exit(0);
/* NOTREACHED */
diff -Napru nmail/quit.c nmail.relax/quit.c
--- nmail/quit.c 2013-12-09 13:16:52.000000000 +0100
+++ nmail.relax/quit.c 2013-12-09 18:59:56.000000000 +0100
@@ -95,15 +95,19 @@ writeback(FILE *res)
}
}
#endif
+ srelax_on();
for (mp = get_message(1); mp; mp = next_message(mp))
if ((mp->m_flag & MPRESERVE) || (mp->m_flag & MTOUCH)==0) {
p++;
if (sendmessage(mp, obuf, NULL, NULL, NULL) < 0) {
warn("%s", mailname);
(void)Fclose(obuf);
+ srelax_off();
return -1;
}
+ srelax();
}
+ srelax_off();
#ifdef APPEND
if (res != NULL)
while ((c = getc(res)) != EOF)
@@ -221,16 +225,20 @@ edstop(jmp_buf jmpbuf)
}
trunc(obuf);
c = 0;
+ srelax_on();
for (mp = get_message(1); mp; mp = next_message(mp)) {
if ((mp->m_flag & MDELETED) != 0)
continue;
c++;
if (sendmessage(mp, obuf, NULL, NULL, NULL) < 0) {
warn("%s", mailname);
+ srelax_off();
sig_release();
longjmp(jmpbuf, -1);
}
+ srelax();
}
+ srelax_off();
gotcha = (c == 0 && ibuf == NULL);
if (ibuf != NULL) {
while ((c = getc(ibuf)) != EOF)
@@ -480,17 +488,22 @@ nolock:
}
(void)fchmod(fileno(obuf), 0600);
}
+ srelax_on();
for (mp = get_message(1); mp; mp = next_message(mp))
- if (mp->m_flag & MBOX)
+ if (mp->m_flag & MBOX) {
if (sendmessage(mp, obuf, saveignore, NULL, NULL) < 0) {
warn("%s", mbox);
if (!append)
(void)Fclose(ibuf);
(void)Fclose(obuf);
(void)Fclose(fbuf);
+ srelax_off();
dot_unlock(mailname);
return;
}
+ srelax();
+ }
+ srelax_off();
/*
* Copy the user's old mbox contents back
diff -Napru nmail/strings.c nmail.relax/strings.c
--- nmail/strings.c 2013-12-09 13:16:52.000000000 +0100
+++ nmail.relax/strings.c 2013-12-09 20:08:08.000000000 +0100
@@ -38,6 +38,8 @@ __RCSID("$NetBSD: strings.c,v 1.18 2010/
#endif
#endif /* not lint */
+#include <assert.h>
+
/*
* Mail -- a mail program
*
@@ -60,10 +62,13 @@ __RCSID("$NetBSD: strings.c,v 1.18 2010/
#define NSPACE 25 /* Total number of string spaces */
static struct strings {
char *s_topFree; /* Beginning of this area */
+ char *s_relaxFree; /* Begin of area during relaxation */
char *s_nextFree; /* Next alloctable place here */
size_t s_nleft; /* Number of bytes left here */
} stringdope[NSPACE];
+static int relaxation;
+
/*
* Allocate size more bytes of space and return the address of the
* first byte to the caller. An even number of bytes are always
@@ -97,6 +102,7 @@ salloc(size_t size)
sp->s_topFree = malloc(STRINGSIZE << idx);
if (sp->s_topFree == NULL)
errx(EXIT_FAILURE, "No room for space %d", idx);
+ sp->s_relaxFree = NULL;
sp->s_nextFree = sp->s_topFree;
sp->s_nleft = STRINGSIZE << idx;
}
@@ -131,13 +137,64 @@ sreset(void)
if (noreset)
return;
+
+ relaxation = 0;
+
idx = 0;
- for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) {
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; ++idx, ++sp) {
if (sp->s_topFree == NULL)
continue;
+ sp->s_relaxFree = NULL;
sp->s_nextFree = sp->s_topFree;
sp->s_nleft = STRINGSIZE << idx;
- idx++;
+ }
+}
+
+PUBLIC void
+srelax_on(void)
+{
+ struct strings *sp;
+ int idx;
+
+ assert(relaxation == 0);
+
+ idx = 0;
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; ++idx, ++sp) {
+ if (sp->s_topFree == NULL)
+ continue;
+ sp->s_relaxFree = sp->s_nextFree;
+ }
+
+ relaxation = 1;
+}
+
+PUBLIC void
+srelax_off(void)
+{
+ assert(relaxation == 1);
+
+ srelax();
+ relaxation = 0;
+}
+
+PUBLIC void
+srelax(void)
+{
+ struct strings *sp;
+ int idx;
+
+ assert(relaxation == 1);
+
+ idx = 0;
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; ++idx, ++sp) {
+ if (sp->s_topFree == NULL)
+ continue;
+ sp->s_nleft = STRINGSIZE << idx;
+ if ((sp->s_nextFree = sp->s_relaxFree) == NULL)
+ sp->s_nextFree = sp->s_topFree;
+ else
+ sp->s_nleft -= (size_t)(uintptr_t)(sp->s_relaxFree -
+ sp->s_topFree);
}
}
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.