delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/07/05/11:30:12

Message-ID: <MAPI.Id.0016.00333138303633303030303930303055@MAPI.to.RFC822>
In-Reply-To: <Pine.SUN.3.91.990704162011.13333W-100000@is>
References: Conversation <MAPI DOT Id DOT 0016 DOT 00333138303633303030303930303053 AT MAPI DOT to DOT RFC822> with last message <Pine DOT SUN DOT 3 DOT 91 DOT 990704162011 DOT 13333W-100000 AT is>
Priority: Normal
X-MSMail-Priority: Normal
X-Priority: 3
To: "Eli Zaretskii" <eliz AT is DOT elta DOT co DOT il>
Cc: djgpp-workers AT delorie DOT com, pavenis AT lanet DOT lv, sandmann AT clio DOT rice DOT edu
MIME-Version: 1.0
From: "Erik Berglund" <erik2 DOT berglund AT telia DOT com>
Subject: Re: Re: gcc-crash - and a possible solution
Date: Mon, 05 Jul 99 17:19:26 +0100 (DJG)
Reply-To: djgpp-workers AT delorie DOT com
X-Mailing-List: djgpp-workers AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

Eli Zaretskii wrote:

> > In win3.11 DOS box, first lp-value looks ok:
> > local turn 1: lp = 0x292004   (lp->prev = 0x472450)
>
> Where did this lp->prev pointer come from?

I've continued to run CC1 with the 3-program testcase and
my own built-in software "dataprobe", and it looks like the
data change is happening in:

Call number 272 to _obstack_newchunk, inside xmalloc.
Call number 609 to xmalloc, inside malloc.

xmalloc-call number 608, goes well:
xmalloc:
   call malloc(), returns 0x292004
   return

xmalloc-call number 609:
The malloc itself goes well, but the data in the previously
allocated block is changed during the malloc call.
xmalloc:
   dataprobe: @0x292004 = 0x292fec    
   call malloc(), returns 0x294004
   dataprobe: @0x292004 = 0x243d5450
   return;

There are no more calls to xmalloc, instead CC1 
crashes in obstack_free:
0x292004 represents lp->limit (0(%edx))
0x292008 represents lp->prev (4(%edx))

lp->limit is changed from a valid pointer (0x292fec) to
"PT=$", which comes from my first environment-
variable "PROMPT=$P$G".

lp->prev is changed to "P$G", which comes
from the rest of "PROMPT=$P$G", and this is the
immediate reason to why CC1 crashes later in obstack_free.

So in some way, malloc accidently changes or remaps
the data in a pre-allocated block, during the process 
of allocating another block.

Now I think I'm going to investigate if it's a real data
change or just a remapping, by for instance writing to 
@0x292004 and see where in memory the data appears.

If it's a remapping, I don't think malloc could do that,
even if it wanted to, then it's probably win3.11 DPMI
who is a little confused.

There is another possibility though: The previously
allocated block may just have been accidently free'd
and now malloc thinks it's free for use. Maybe it's a
good idea to "dataprobe" all calls to free and realloc
as well. But even so it's hard to explain the sudden
appearance of the new interesting PROMPT=$P$G data.

Do you know if CC1 or other programs normally use
high addresses (>2Gb) when run under win95?
Maybe the problem only appears in win3.11,
and only if high addresses are used.

If anyone wants to look att the CC1 2.7.2.1/DJGPP 2.01
sources and binaries, they can be downloaded from:
ftp://ftp.sunet.se/pub2/pc/mirror/Coast/vendors/djgpp

> >   /* We use >= because there cannot be an object at the beginning of a
chunk.
> >      But there can be an empty object at that address
> >      at the end of another chunk.  */
> >   while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
> 
> Based on Charles' recommendations, I would suspect the comparisons
> here, due to the signed/unsigned issue.  Perhaps it would be a good
> idea to look at the values that are compared and see if that explains
> something.

I've checked the "lp" values and they are always around 0x100000 -
and 0x400000, no high addresses are used, even when CC1 crashes.
The same goes for "obj" and "lp->limit", so the comparisons seem to be
right at this stage.

> Btw, what is the definition of POINTER in the above line?

It's defined in obstack.c as: #define POINTER char *

For your information, I have included xmalloc (from toplev.c)
and _obstack_newchunk (from obstack.c) below:

/* Same as `malloc' but report error if no memory available.  */

char *
xmalloc (size)
     unsigned size;
{

/* ***dataprobe: previous block ok */

  register char *value = (char *) malloc (size);

/* ***dataprobe: previous block has changed */

  if (value == 0)
    fatal ("virtual memory exhausted");
  return value;
}

Start of _obstack_newchunk:

/* Allocate a new current chunk for the obstack *H
   on the assumption that LENGTH bytes need to be added
   to the current object, or a new object of length LENGTH allocated.
   Copies any partial object from the end of the old chunk
   to the beginning of the new one.  */

void
_obstack_newchunk (h, length)
     struct obstack *h;
     int length;
{
  register struct _obstack_chunk*	old_chunk = h->chunk;
  register struct _obstack_chunk*	new_chunk;
  register long	new_size;
  register int obj_size = h->next_free - h->object_base;
  register int i;
  int already;

  /* Compute size for new chunk.  */
  new_size = (obj_size + length) + (obj_size >> 3) + 100;
  if (new_size < h->chunk_size)
    new_size = h->chunk_size;

  /* Allocate and initialize the new chunk.  */
  new_chunk = CALL_CHUNKFUN (h, new_size);
  if (!new_chunk)
    {
      h->alloc_failed = 1;
      return;
    }
  h->alloc_failed = 0;
  h->chunk = new_chunk;
  new_chunk->prev = old_chunk;
  new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;

  /* Move the existing object to the new chunk.
     Word at a time is fast and is safe if the object
     is sufficiently aligned.  */
  if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
    {
      for (i = obj_size / sizeof (COPYING_UNIT) - 1;
	   i >= 0; i--)
	((COPYING_UNIT *)new_chunk->contents)[i]
	  = ((COPYING_UNIT *)h->object_base)[i];
      /* We used to copy the odd few remaining bytes as one extra
COPYING_UNIT,
	 but that can cross a page boundary on a machine
	 which does not do strict alignment for COPYING_UNITS.  */
      already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
    }
  else
    already = 0;
  /* Copy remaining bytes one by one.  */
  for (i = already; i < obj_size; i++)
    new_chunk->contents[i] = h->object_base[i];

  /* If the object just copied was the only data in OLD_CHUNK,
     free that chunk and remove it from the chain.
     But not if that chunk might contain an empty object.  */
  if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
    {
      new_chunk->prev = old_chunk->prev;
      CALL_FREEFUN (h, old_chunk);
    }

  h->object_base = new_chunk->contents;
  h->next_free = h->object_base + obj_size;
  /* The new chunk certainly contains no empty object yet.  */
  h->maybe_empty_object = 0;
}

End of _obstack_newchunk.

Erik


- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019