bug-cvs
[Top][All Lists]
Advanced

[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 18:00:19 -0500
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113

Ignore my very last comments about xrealloc_and_strcat not needing newsize. I wasn't thinking; it does need it for the while loop that is in the cvs 1.12.6 version of expand_string.

Chris

Chris Bohn wrote:

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)
being
while (0 < 7)

in the full function:

void
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;
    }
    }
  else
    {
      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).

Chris


Derek Robert Price wrote:

-----BEGIN PGP SIGNED MESSAGE-----
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:


void
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.

Derek

- --
                *8^)

Email: address@hidden

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

iD8DBQFAY0kNLD1OTBfyMaQRAjpXAJ4qnRzoDgLnNVAHO5kxRee9Zz4PHwCfaQ8s
92LRHhNFESk5mUApftthq2k=
=d9f4
-----END PGP SIGNATURE-----









reply via email to

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