Message-ID: In-Reply-To: References: Conversation with last message Priority: Normal X-MSMail-Priority: Normal X-Priority: 3 To: "Eli Zaretskii" 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" Subject: Re: Re: gcc-crash - and a possible solution Date: Mon, 05 Jul 99 17:19:26 +0100 (DJG) Content-Type: text/plain; charset="ISO-8859-1"; X-MAPIextension=".TXT" Content-Transfer-Encoding: 7bit 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 Precedence: bulk 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