Mail Archives: djgpp-workers/1999/07/05/11:30:12
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 -