Re: EU 3.0.1 -- there's probably a bug in there somewhere

new topic     » goto parent     » topic index » view thread      » older message » newer message

Robert Craig wrote:
> Pete Lomax wrote:
> > Matt Lewis wrote:
> > > Here's some simpler code that causes a crash.
> > Confirmed here too, on 3.0.0 but not 2.4, 2.5, or cb-3.0.1.
> > > However, after rebuilding from source, I wasn't getting the crash
> > No way to know if a source mod fixes it then...
> > 
> > I had a quick hack and it appears to be crashing on my system in routine
> > restore_privates,
> > in the code:
> > 
> >         // restore the current task's private data (will always be there)
> > 
> >         block = load_private_block(this_routine, current_task);
> > 
> >         // private vars
> >         sym = this_routine->next;
> >         while (sym != NULL && sym->scope <= S_PRIVATE) {
> >             sym->obj = *block++;
> >             sym = sym->next;
> >         }
> > 
> > it crashes on the sym->obj = *block statement. A chunk of heap ends at
> > #004D5FFF
> > and when it crashes block is #004D6000. sym is correctly pointing at the
> > parameter
> > r. I have not studied load/save_private_block, but that is where my
> > suspicions
> > would lie. A random thought I had is that if it were saving and loading
> > everything
> > out-by-one, it might well appear to work fine in 99.9% of cases. Or maybe
> > not.
> 
> Thanks to everyone for helping pin this down.
> I'll be able to look at this later today (in a few hours).
> As you suggest, it could be that I'm allocating slightly less memory 
> than I need in some cases. That would cause occasional crashes
> that might go away with just a trivial change in the user's program.

I wasn't able to duplicate the crash, but I've found a bug 
in load_private_block() that could very well be the cause.

static object *load_private_block(symtab_ptr routine, int task)
// Retrieve a private block and remove it from the list for this routine.
// We know that the block will be there, often near the start of the list.
{
    struct private_block *p;
    struct private_block *prev_p;
    struct private_block *defunct;
    object *block;

    p = routine->u.subp.saved_privates; // won't be NULL
    prev_p = NULL;

    while (TRUE) {
        if (p->task_number == task) {
            block = (object *)&(p->block);

            // unlink it
            if (prev_p == NULL) {
                routine->u.subp.saved_privates = p->next;
            }
            else {
                prev_p->next = p->next;
            }

            EFree(p); // BUG: too soon!!!
            return block;
        }
        prev_p = p;
        p = p->next;
    }
}

In the C code above, I've made the mistake of freeing block p, 
*then* returning a pointer into it. The caller uses that pointer
to retrieve some data. EFree() would usually just put p onto a 
list, but if the storage cache is getting too full (over 2000 blocks), 
it will actually call free(), which, on Windows, could occasionally
result in modification of the freed block, perhaps merging it with 
an adjacent block, shrinking the heap or something.

(Originally, "block" was a separately allocated block of memory, 
but for efficiency, I combined it into block p using a C coding trick.)

The fix is easy since load_private_block() is only called
from one place. I just have to retrieve the data from block p,
*before* calling EFree().

I'll check the new code in tomorrow.
Maybe we need 3.0.2 soon.

Regards,
   Rob Craig
   Rapid Deployment Software
   http://www.RapidEuphoria.com

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu