[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: patch: under Windows, cvs status reports "memory exhausted"

From: Chris Bohn
Subject: Re: patch: under Windows, cvs status reports "memory exhausted"
Date: Thu, 25 Mar 2004 17:58:14 -0500
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113

I executed
cvs -d :pserver:admiral:/zip/tmp/cbohn/cvstest stat subr.c
from within the cvs src directory.

On the first invocation of xrealloc_and_strcat

xrealloc_and_strcat (&line, &line_len, node->key);

line 4318 of client.c (cvs 1.12.6 source)

line = ""
line_len = 0
node->key = subr.c

That calls causes the error.

Upon getting into expand_string from xrealloc_and_strcat:

expand_string (char **strptr, size_t *n, size_t newsize)

*strptr = ""
*n = 0
newsize = 7 (calculated in xrealloc_and_strcat from strlen (*str) + strlen (src) + 1 --> 0 + 6 + 1)

So we now have:
while (*n < newsize)
while (0 < 7)

in the full function:

expand_string (char **strptr, size_t *n, size_t newsize)
    while (*n < newsize)
        *strptr = x2realloc (*strptr, n);

The x2realloc call is the one that dies.

x2realloc calls x2nrealloc_inline (p, pn, 1);
being logically equivalent to x2nrealloc_inline ("", 0, 1);

Here is that function:
static inline void *
x2nrealloc_inline (void *p, size_t *pn, size_t s)
  size_t n = *pn;

  if (! p)
      if (! n)
          /* The approximate size to use for initial small allocation
             requests, when the invoking code specifies an old size of
             zero.  64 bytes is the largest "small" request for the
             GNU C library malloc.  */
          enum { DEFAULT_MXFAST = 64 };

          n = DEFAULT_MXFAST / s;
          n += !n;
      if (SIZE_MAX / 2 / s < n)
        xalloc_die ();
      n *= 2;

  *pn = n;
  return xrealloc (p, n * s);

removing inline so I could debug into in the IDE, it revealed it hits the else of "if (! p)" because p was allocated back in client.c:

char *line = xmalloc (1);
*line = '\0';

so in this case, the if above the xalloc_die isn't called because the expr is > 0, so n and *pn get set to 0*2 = 0 still.

xrealloc (p, n * s) gets called with "", 0*1 --> xrealloc ("", 0)
that calls
xnrealloc_inline (p, n, 1);
and xalloc_die is called from
if (xalloc_oversized (n, s) || ! (p = realloc (p, n * s)))

xalloc_oversized is false, but since realloc is called like
realloc(p, 0), it reallocs the block to 0, and !0 = 1, so it dies. I thought I would step through the runtime a little more, and I found:

         * ANSI: realloc(pUserData, 0) is equivalent to free(pUserData)
         * (except that NULL is returned)
        if (fRealloc && nNewSize == 0)
            _free_dbg(pUserData, nBlockUse);
            return NULL;

so that explains the problem. I apologize for not digging in this much initially, but when initially debugging, the debugger wasn't going where I expected because of the inline calls, so I just thought something was messed up and ignored the problem. So the solution to this problem is debatable. Should client.c not xmalloc(1), should x2nrealloc_inline be smarter and not just check !p, etc.? Changing x2nrealloc_inline sounds like the best way to me. You could do something like checking for a zero len string and size allocated only being 1, but you have to cast everything from the void *, which likely isn't desirable. I can't really find any docs on what these x2 functions are supposed to do (exact specs), so I don't know if they should change or if the caller (client.c) should have known the proper usage. Either way, it is a bad error coming out of x2realloc, so that should change at a minimum to return a better error if 0 isn't valid with an already allocated string. My fix will still work, but it is allocating more than it needs in the case of already allocated string and 0 current size. If all stays as is, xrealloc_and_strcat (in subr.c) should change to not calculate and send newsize because it isn't needed or used if x2realloc starts with the original size (lenp).


Derek Robert Price wrote:

Hash: SHA1

Chris Bohn wrote:

x2realloc wasn't the problem; it was the wrapper function around it,
expand_string, which is called from xrealloc_and_strcat.

x2realloc (str, size) doubles *size (setting it in the process), and
returns xrealloc (str, *size).  This is exactly what expand_string()
used to be doing.

There should also be no difference in the behavior of expand_string() or
x2realloc() between UNIX & Windows.  Can you provide a debugger stack
trace for the `cvs status' failure you reported?

Once again:

expand_string (char **strptr, size_t *n, size_t newsize)
   while (*n < newsize)
   *strptr = x2realloc (*strptr, n);

The first line will likely always be true because this function is
called to append two strings in this case.

No, it won't.  In your example above, x2realloc(*strptr, n) doubles *n
with each invocation.  Please provide a stack trace.


- --

Email: derek@ximbiot.com

Get CVS support at <http://ximbiot.com>!
Version: GnuPG v1.2.1 (GNU/Linux)
Comment: Using GnuPG with Netscape - http://enigmail.mozdev.org


reply via email to

[Prev in Thread] Current Thread [Next in Thread]