This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: 1.5.19: changes have broken Qt3


[ I realized that a couple of points in this thread were never addressed -- we
sort of got side tracked on the GDB issue.  I just want to reply to these points
and try to convince you that this bug you see does not exist.  People have a
tendency to point to the archives and say "lookee, it's broken" if the thread
does not come to a result. ]

Ralf Habacker wrote:

> You said that the testcase runs, yes, but do you have tried to debug the
> cygwin dll with this exception handling. Please start the above
> mentioned testcase in gdb and enter
> 
> b main
> r
> b pthread_mutexattr::pthread_mutexattr()
> c
> 
> This breakpoint is never reached (at least in released gdb) and makes it
> hard to debug cygwin's threading stuff, probably impossible in this area.

The breakpoint does not fire, correct.  But that is because pthread_mutexattr's
constructor is empty (other than the initialization list):

pthread_mutexattr::pthread_mutexattr ():verifyable_object
(PTHREAD_MUTEXATTR_MAGIC),
pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_ERRORCHECK)
{
}

If instead you set a breakpoint for the desired line that calls the constructor
(in this case, thread.cc:3027) then it does fire.  And if you use a CVS GDB you
get no spurious faults either.

> This means to be able to debug the cygwin dll in this area I have to
> recompile a special cygwin version with something like below mentioned.:
> 
> /* FIXME: write and test process shared mutex's.  */
> extern "C" int
> pthread_mutexattr_init (pthread_mutexattr_t *attr)
> 
> old:
>   if (pthread_mutexattr::is_good_object (attr))
>     return EBUSY;
> 
> new:
>   if (attr && pthread_mutexattr::is_good_object (attr))
>     return EBUSY;

This is totally useless.  In order for "if (attr)" to be false, the function
would have had to been called as pthread_mutexattr_init (NULL) rather than
pthread_mutexattr_init (&some_as_yet_uninitialized_variable).  Furthermore, if
attr really were false, then the next line:

  *attr = new pthread_mutexattr ();

would cause a NULL dereference which would not be caught, causing the program to
crash and burn.  The function must always be passed a valid pointer; the thing
it points to might be uninitialized though.

Let's walk through the complete series of events that happens in the testcase
below:

pthread_mutexattr_t mxAttr;
assert(pthread_mutexattr_init(&mxAttr) == 0);

This is the thing that you claim is broken, however if you run this testcase
from a regular prompt (outside GDB) it does not assert, and in fact the
mutexattr is correctly initialized.  (And if you do run it in a recent GDB it
does not assert nor fault either.)

Let's look at the entire chain of code involved here:

extern "C" int
pthread_mutexattr_init (pthread_mutexattr_t *attr)
{
  if (pthread_mutexattr::is_good_object (attr))
    return EBUSY;

  *attr = new pthread_mutexattr ();
  if (!pthread_mutexattr::is_good_object (attr))
    {
      delete (*attr);
      *attr = NULL;
      return ENOMEM;
    }
  return 0;
}

inline bool
pthread_mutexattr::is_good_object (pthread_mutexattr_t const * attr)
{
  if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) !=
                                         VALID_OBJECT)
    return false;
  return true;
}

static inline verifyable_object_state
verifyable_object_isvalid (void const * objectptr, long magic, void
                           *static_ptr1, void *static_ptr2, void *static_ptr3)
{
  verifyable_object **object = (verifyable_object **) objectptr;

  myfault efault;
  if (efault.faulted ())
    return INVALID_OBJECT;

  if ((static_ptr1 && *object == static_ptr1) ||
      (static_ptr2 && *object == static_ptr2) ||
      (static_ptr3 && *object == static_ptr3))
    return VALID_STATIC_OBJECT;
  if ((*object)->magic != magic)
    return INVALID_OBJECT;
  return VALID_OBJECT;
}

So, the call chain will look like this:

pthread_mutexattr_init(&mxAttr)  ->  
 pthread_mutexattr::is_good_object (&mxAttr)  -> 
  verifyable_object_isvalid (&mxAttr, PTHREAD_MUTEXATTR_MAGIC, NULL,NULL,NULL)

Of course, these last two functions will be expanded inline, so this will all
occur in the context of pthread_mutexattr_init.  We are at the point in
verifyable_object_isvalid of:

  if ((*object)->magic != magic)

Here, object is &mxAttr, so *object is mxAttr.  But mxAttr is not yet
initialized, so dereferencing it as mxAttr->magic causes a fault.  This causes
verifyable_object_isvalid to return INVALID_OBJECT through the "if
(efault.faulted ())" branch.

Consequently, the if() condition in pthread_mutexattr::is_good_object is true,
the function returns false, the if() condition at the beginning of
pthread_mutexattr_init is false, and execution continues to the line "*attr =
new pthread_mutexattr ()", and finally mxAttr is initialized just as we desire.

I hope that I have shown that even though a fault occurs that execution
continues normally and the mutexattr IS initialized correctly.

Brian

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]