From jeffrey.horner at gmail.com  Fri Nov 11 05:54:09 2011
From: jeffrey.horner at gmail.com (Jeffrey Horner)
Date: Thu, 10 Nov 2011 22:54:09 -0600
Subject: [Rd] When collected warnings exceeds 50
Message-ID: <CAD+yNFjt51Jch5XnnX-mXjzeAW7Qeqemha97SdmpL=qS2hgfMQ@mail.gmail.com>

Hi,

I've been tracking down a memory leak in an rApache application,
http://data.vanderbilt.edu/rapache/bbplot. The code was deployed in
2007 and has survived numerous upgrades of both R and rApache
(including upgrades and bugs in RMySQL). It's written in such a way so
that web crawlers will download every possible URL the app will
create. It's not a high-traffic app, but just about every line of code
is executed at some point during a crawl by Google, Bing, etc.

Here's the salient point: the app (well, just about all rApache apps)
sets option warn to 0 to collect all warnings until a request is
completed. It turns out that some requests will collect more than 50
warnings, and the result is an apache process that leaks memory until
finally seg faulting somewhere in one of R's extra packages, if I
recall correctly.

After what seems like a month working on this problem, I think I've
narrowed it down to a simple test case. I'm testing with R-devel
r57624 on ubuntu linux. Running the following under valgrind:

R -d valgrind
> options(warn=0)
> for (i in 1:51) factor(1,levels=c(1,1) # duplicate level warningcall

and you should see "Invalid read" messages. I've narrowed it down to
vwarningcall_dflt starting a new R context via begincontext()  but
returning early without calling endcontext() in errors.c:

 svn diff src/main/errors.c
Index: src/main/errors.c
===================================================================
--- src/main/errors.c	(revision 57624)
+++ src/main/errors.c	(working copy)
@@ -333,8 +333,11 @@
 	char *tr; int nc;
 	if(!R_CollectWarnings)
 	    setupwarnings();
-	if( R_CollectWarnings > 49 )
+	if( R_CollectWarnings > 49 ) {
+	    endcontext(&cntxt);
+	    inWarning = 0;
 	    return;
+	}
 	SET_VECTOR_ELT(R_Warnings, R_CollectWarnings, call);
 	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
 	if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)

This fix eliminates the "Invalid read" errors, but I'm unsure if it
fixes my application. I'll find out tomorrow.

Jeff



[Rd] When collected warnings exceeds 50
Jeffrey Horner