help-gplusplus
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: double free or corruption - it works on older machine


From: alan . larkin
Subject: Re: double free or corruption - it works on older machine
Date: 16 Aug 2006 10:55:29 -0700
User-agent: G2/0.2

Hi Ulrich.

Thanks for your interest.

Ulrich Eckhardt wrote:
> alan.larkin@gmail.com wrote:
> > I have software that works on an old machine:
> > Linux 2.4.20-8smp #1 SMP i686 i686 i386 GNU/Linux
> > gcc (GCC) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
> >
> > But not on a new one:
> > Linux 2.6.15-26-amd64-generic #1 SMP PREEMPT x86_64 GNU/Linux
> > gcc (GCC) 4.0.3 (Ubuntu 4.0.3-1ubuntu5)
> > (also has gcc 3.3 and 3.4)
>
> Those numbers are mostly irrelevant, the question rather is which
> malloc/free implementations you use. You might be able to reproduce the
> error on the older system by upgrading the glibc.

Im afraid I have restricted access on the old machine.

> > I get a "*** glibc detected *** double free or corruption (!prev):
> > 0x00002aaabc610420 ***" error which IMHO is a scurrilous lie ... I dont
> > see anything wrong with the code which has been working for a long
> > time.
>
> Hahahaa. Believe me, we all had cases where we would have sworn that the
> code is okay but it wasn't. Show the code first. Also, does it compile
> without warnings and does it follow guidelines for safe, modern C++?

I get the following warnings from the class which I believe might be
the source of the problem (see below) but I do not believe them to be
significant (the j-types are from Javas jni.h):

In file included from MTWM.cpp:33:
MTWM.h: In static member function `static int MTWM::encodeJFloat(float,
char*)
   ':
MTWM.h:251: warning: converting to `unsigned int' from `jfloat'
MTWM.h: In static member function `static int
MTWM::encodeJDouble(double,
   char*)':
MTWM.h:307: warning: converting to `long int' from `jdouble'

Otherwise, I have tried to program well, but who am I to say that I
have succeeded.

> > Things are greatly complicated by the fact that the new machine is
> > AMD64, this software is a plugin loaded dynamically by (Sun) java so
> > gdb isnt an option I dont think, and that I am stuck with java version
> > 1.5.
>
> Why not? Of course you can attach GDB to a process while it's running. BTW,
> just to name an example, in C you can get away without a malloc()
> declaration and still use it as long as a pointer has the same size as an
> int, while this is sure to break on e.g. 64 bit machines. Similar
> assumptions about the size of types have proven fatal to other programs,
> too which then broke as soon as someone put them on a 64 bit system.
>
So I can launch a java process ($java -XrunMYLIB ...) and attach gdb to
the MYLIB stuff!? Any chance you know how?

Anyway, code. Theres quite a bit of it. But I have determined that by
disabling one event (this is event driven software - a JVMPI profiler)
I avoid the error, so the code to handle this event follows.

It intercepts the event, invokes a function (in a dynamically loaded
class) to encode it in some format, and then writes the resulting bytes
to an ostream. The memory used to store the encoding is then freed.
This same process is used for several other events without difficulty
so common elements, e.g. encodeJByte or encodeJInt or the actual
outputting of the bytes, are not the problem. If there is a problem
with my code it should be visible below.

<in Forrest_Handlers.cpp>
/* Event dispathing function */
void
Forrest::notifyEvent(JVMPI_Event* const event)
{
  switch(event->event_type)
  {
    ...
    case JVMPI_EVENT_CLASS_LOAD:
    case JVMPI_EVENT_CLASS_LOAD | JVMPI_REQUESTED_EVENT:
    {
       classLoadHandler(
         event->env_id,
         event->u.class_load.class_name,
         event->u.class_load.source_name,
         event->u.class_load.num_interfaces,
         event->u.class_load.num_methods,
         event->u.class_load.methods,
         event->u.class_load.num_static_fields,
         event->u.class_load.statics,
         event->u.class_load.num_instance_fields,
         event->u.class_load.instances,
         event->u.class_load.class_id,
         event->event_type & JVMPI_REQUESTED_EVENT);
       break;
    }
    ...
  }
}

void
classLoadHandler(JNIEnv* const envID, const char* const name, const
char* const srcName, const int numInterfaces, const int numMethods,
const JVMPI_Method* const methods, const int numStatics, const
JVMPI_Field* const statics, const int numInstances, const JVMPI_Field*
const instances, const jobjectID classID, const int requested)
{
  /**
   * Memory is allocated for encoding from within a dynamic
library/module. Care
   * should be taken to free that memory from within that
library/module using
   * its fre(void*) method.
   */
  char* encoding;
  int length = FORREST(m_protocol)->classLoad(encoding, envID, name,
srcName, numInterfaces, numMethods, methods, numStatics, statics,
numInstances, instances, classID, requested);
  threadGetLocalData(envID)->getOstream()->write(encoding, length);
  FORREST(m_protocol)->fre(encoding);
}

---
FORREST(m_protocol) refers to an instance of another dynamically loaded
class. In the test instance the relevant code is:
---

<in MTWM.cpp>
int
MTWM::classLoad(char*& c, JNIEnv* const envID, const char* const name,
const char* const srcName, const int numInterfaces, const int
numMethods, const JVMPI_Method* const methods, const int numStatics,
const JVMPI_Field* const statics, const int numInstances, const
JVMPI_Field* const instances, const jobjectID classID, const int
requested)
{
  int size = SIZEOF_JBYTE +
    SIZEOF_JLONG +
    SIZEOF_JNIENVP +
    SIZEOF_JSHORT + strlen(name) +
    SIZEOF_JSHORT + strlen(srcName) +
    SIZEOF_JSHORT +
    SIZEOF_JOBJECTID;
  for(int i = 0; i < numMethods; i++)
  {
    size = size +
      SIZEOF_JSHORT + strlen(methods[i].method_name) +
      SIZEOF_JSHORT + strlen(methods[i].method_signature) +
      SIZEOF_JINT;
  }

  c = new char[size];
  if(!c)
  {
    /* Out of memory */
    error("Out of memory.");
    /* Never get here */
  }

  int index = 0;
  index += encodeJByte(FORREST_PROTOCOL_CLASS_LOAD, c + index);
  index += encodeJLong(m_eventNumber++, c + index);
  index += encodeJNIEnvP(envID, c + index);
  index += encodeUTF8(name, c + index);
  index += encodeUTF8(srcName, c + index);
  index += encodeJShort(numMethods, c + index);
  for(int i = 0; i < numMethods; i++)
  {
    index += encodeUTF8(methods[i].method_name, c + index);
    index += encodeUTF8(methods[i].method_signature, c + index);
    index += encodeJmethodID(methods[i].method_id, c + index);
  }
  index += encodeJobjectID(classID, c + index);
  return size;
}

<in MTWM.h>
public virtual void
fre(void* arg)
{
    free(arg);
}

If I add debugging statements to classLoadHandler I see that it
finishes and several other events arrive before the crash happens. But
as I said, it is this event that seems to be the origin of the problem.



reply via email to

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