[OGo-GNUstep-Port] experiences with OGo and gunstep-base on OpenBSD

Sebastian Reitenbach gnustep-port@opengroupware.org
Mon, 28 May 2007 12:21:05 +0200


Hi,

I updated the GNUstep ports that are available for OpenBSD 4.1, containing 
the latest gnustep-make 2.0.1 and gnustep-base 1.15.0.[1] I created 
additional ports for Sope, mod_ngobjweb and OGo[2]. The ports are based on 
the trunk versions of sope and ogo. They all compile and install fine.

After compiling and configuring, ogo did started successfully. but after 
trying to login, it crashed. It took me some while to not install stripped 
versions of it, to be able to debug the problem. 

There seems to be two problems:
1. in gnustep-base NSAutoreleasePool.m:404
2. in gnustep-base NSKeyValueCoding.m:350

commenting out these two lines and recompiling, then everything seems to 
work. I was able to login, search contacts, write mail, ....

below the gdb stack traces from the crashes and exception:

(gdb) bt
#0  0x00000000 in ?? ()
#1  0x08284718 in -[NSAutoreleasePool emptyPool] (self=0x81e8b888, 
_cmd=0x282eba10) at NSAutoreleasePool.m:404
#2  0x08284492 in -[NSAutoreleasePool dealloc] (self=0x81e8b888, 
_cmd=0x282eba08) at NSAutoreleasePool.m:323
#3  0x08284447 in -[NSAutoreleasePool release] (self=0x81e8b888, 
_cmd=0x240b04b8) at NSAutoreleasePool.m:316
#4  0x040b59ae in -[LSDBFetchRelationCommand _executeInContext:] 
(self=0x8a28f808, _cmd=0x29979b80, _context=0x8b5a1208)
    at LSDBFetchRelationCommand.m:287
#5  0x09984a63 in -[LSFetchExtendedAttributesCommand _executeInContext:] 
(self=0x8a28f808, _cmd=0x240b0bc8, _context=0x8b5a1208)
    at LSFetchExtendedAttributesCommand.m:145
#6  0x040b75de in -[LSDBObjectBaseCommand primaryRunInContext:] 
(self=0x8a28f808, _cmd=0x240ae798, _context=0x8b5a1208)
    at LSDBObjectBaseCommand.m:186
#7  0x040add8c in -[LSBaseCommand runInContext:] (self=0x8a28f808, 
_cmd=0x240ae6f8, _context=0x8b5a1208) at LSBaseCommand.m:192
#8  0x040ad678 in LSCommandRunV (_ctx=0x8b5a1208, _factory=0x83ac3b08, 
_domain=0x2fa2df18, _command=0x2fa2df24) at LSBaseCommand.m:84
#9  0x0fa3108d in -[LSLoginAccountCommand _executeInContext:] 
(self=0x8b5a1808, _cmd=0x240b0bc8, _context=0x8b5a1208)
    at LSLoginAccountCommand.m:249
#10 0x040b75de in -[LSDBObjectBaseCommand primaryRunInContext:] 
(self=0x8b5a1808, _cmd=0x240ae798, _context=0x8b5a1208)
    at LSDBObjectBaseCommand.m:186
#11 0x040add8c in -[LSBaseCommand runInContext:] (self=0x8b5a1808, 
_cmd=0x240af6f0, _context=0x8b5a1208) at LSBaseCommand.m:192
#12 0x040b23ce in runCommand (self=0x8b5a1208, _command=0x8b5a1808) at 
LSCommandContext.m:870
#13 0x040b0957 in -[LSCommandContext runCommand:vargs:] (self=0x8b5a1208, 
_cmd=0x240b9a00, _command=0x240b9bf4, _va=0xcfbdc890)
    at LSCommandContext.m:457
...






(gdb) list NSAutoreleasePool.m:404
399                       else
400                         {
401                           imps[hash] = [c methodForSelector: 
releaseSel];
402                         }
403                     }
404                   (imps[hash])(anObject, releaseSel);
405                 }
406               _released_count -= released->count;
407               released->count = 0;
408               released = released->next;




- (void) emptyPool
{
  unsigned      i;
  Class         classes[16];
  IMP           imps[16];

  for (i = 0; i < 16; i++)
    {
      classes[i] = 0;
      imps[i] = 0;
    }

  /*
   * Loop throught the deallocation code repeatedly ... since we deallocate
   * objects in the receiver while the receiver remains set as the current
   * autorelease pool ... so if any object which is being deallocated adds
   * any object to the current autorelease pool, we may need to release it
   * again.
   */
  while (_child != nil || _released_count > 0)
    {
      volatile struct autorelease_array_list *released = _released_head;

      /* If there are NSAutoreleasePool below us in the stack of
         NSAutoreleasePools, then deallocate them also.  The (only) way we
         could get in this situation (in correctly written programs, that
         don't release NSAutoreleasePools in weird ways), is if an
         exception threw us up the stack. */
      if (_child != nil)
        {
          [_child dealloc];
        }

      /* Take the object out of the released list just before releasing it,
       * so if we are doing "double_release_check"ing, then
       * autoreleaseCountForObject: won't find the object we are currently
       * releasing. */
      while (released != 0)
        {
          id    *objects = (id*)(released->objects);

          for (i = 0; i < released->count; i++)
            {
              id        anObject = objects[i];
              Class     c = GSObjCClass(anObject);
              unsigned  hash = (((unsigned)(uintptr_t)c) >> 3) & 0x0f;

              objects[i] = nil;
              if (classes[hash] != c)
                {
                  classes[hash] = c;
                  if (GSObjCIsInstance(anObject))
                    {
                      imps[hash] = [c instanceMethodForSelector: 
releaseSel];
                    }
                  else
                    {
                      imps[hash] = [c methodForSelector: releaseSel];
                    }
                }
              (imps[hash])(anObject, releaseSel);
            }
          _released_count -= released->count;
          released->count = 0;
          released = released->next;
        }
    }
}


- (void)_executeInContext:(id)_context {
  NSString          *relKey;
  NSArray           *rels;
  NSAutoreleasePool *pool;

  pool   = [[NSAutoreleasePool alloc] init];
  relKey = [self relationKey];
  rels   = [self _fetchRelations];

  // TODO: move section to an own method
  if (![self isToMany] && (relKey != nil)) {
    NSString *srcKey, *destKey, *relKey;
    NSArray  *objs;
    int      i, cnt;

    srcKey  = [self sourceKey];
    destKey = [self destinationKey];
    relKey  = [self relationKey];
    objs    = [self object];

    for (i = 0, cnt = [objs count]; i < cnt; i++) {
      id  obj, pKey;
      int j, cnt2;

      obj  = [objs objectAtIndex:i];
      pKey = [obj valueForKey:srcKey];

      for (j = 0, cnt2 = [rels count]; j < cnt2; j++) {
        NSNumber *fKey;
        id       relObj;

        relObj = [rels objectAtIndex:j];
        fKey   = [relObj valueForKey:destKey];

        if (![pKey isEqual:fKey])
          continue;

        [obj takeValue:relObj forKey:relKey];
      }
    }
  }
  if (relKey == nil)
    [self setReturnValue:rels];

  [pool release]; pool = nil;
}







2007-05-28 12:03:11.906 ogo-webui-1.1[25601] Note: using flat-array message 
notifications!
[Switching to process 25601, thread 0x8b81b000]

Breakpoint 1, -[NSException raise] (self=0x881e4148, _cmd=0x251b9020) at 
NSException.m:782
782       if (GSPrivateEnvironmentFlag("GNUSTEP_STACK_TRACE", NO) == YES
Current language:  auto; currently objective-c
(gdb) bt
#0  -[NSException raise] (self=0x881e4148, _cmd=0x251b9020) at 
NSException.m:782
#1  0x051b3ff9 in -[NSObject(KeyValueCoding) setValue:forUndefinedKey:] 
(self=0x86d58108, _cmd=0x251e0110, anObject=0x86d58528,
    aKey=0x881e40e8) at NSKeyValueCoding.m:350
#2  0x05269beb in GSObjCSetVal (self=0x86d58108, key=0xcfbf98a0 "misc", 
val=0x86d58528, sel=0x0, type=0x0, size=4, offset=-809527136)
    at GSObjCRuntime.m:1810
#3  0x051b320e in SetValueForKey (self=0x86d58108, anObject=0x86d58528, 
key=0xcfbf98a0 "misc", size=4) at NSKeyValueCoding.m:114
#4  0x051b3c0f in -[NSObject(KeyValueCoding) setValue:forKey:] 
(self=0x86d58108, _cmd=0x263a8fe8, anObject=0x86d58528, aKey=0x86d58128)
    at NSKeyValueCoding.m:288
#5  0x063efbf5 in _setValue (self=0x80f4ba08, _value=0x86d58528, 
root=0x8917f988) at WOKeyPathAssociation.m:912
#6  0x063efddd in -[WOKeyPathAssociation setValue:inComponent:] 
(self=0x80f4ba08, _cmd=0x26391790, _value=0x86d58528, _component=0x8917f988)
    at WOKeyPathAssociation.m:934
#7  0x063993d5 in WOComponent_syncToParent (self=0x83157588, 
_parent=0x8917f988) at WOComponent+Sync.m:174
#8  0x0639da12 in WOContext_leaveComponent (self=0x80644808, 
_component=0x83157588) at WOContext.m:444
#9  0x0639dc57 in -[WOContext leaveComponent:] (self=0x80644808, 
_cmd=0x263b09e0, _component=0x83157588) at WOContext.m:469



(gdb) list NSKeyValueCoding.m:350
345         (aKey ? (id)aKey : (id)@"(nil)"), @"NSUnknownUserInfoKey",
346         nil];
347       exp = [NSException exceptionWithName: NSInvalidArgumentException
348                                     reason: @"Unable to set nil value 
for key"
349                                   userInfo: dict];
350       [exp raise];
351     }
352
353
354     - (void) setValuesForKeysWithDictionary: (NSDictionary*)aDictionary




- (void) setValue: (id)anObject forUndefinedKey: (NSString*)aKey
{
  NSDictionary  *dict;
  NSException   *exp;
  static IMP    o = 0;

  /* Backward compatibility hack */
  if (o == 0)
    {
      o = [NSObject instanceMethodForSelector:
        @selector(handleTakeValue:forUnboundKey:)];
    }
  if ([self methodForSelector: @selector(handleTakeValue:forUnboundKey:)] != 
o)
    {
      [self handleTakeValue: anObject forUnboundKey: aKey];
      return;
    }

  dict = [NSDictionary dictionaryWithObjectsAndKeys:
    (anObject ? (id)anObject : (id)@"(nil)"), @"NSTargetObjectUserInfoKey",
    (aKey ? (id)aKey : (id)@"(nil)"), @"NSUnknownUserInfoKey",
    nil];
  exp = [NSException exceptionWithName: NSInvalidArgumentException
                                reason: @"Unable to set nil value for key"
                              userInfo: dict];
  [exp raise];
}


well, I doubt that commenting out the two mentioned lines above is the 
correct solution, but as  I do not really understood the memory management 
yet, I have no idea for a better solution. 

I also have no clue, whether this is gnustep-base fault, or whether there is 
sth. incorrectly usesd in sope/OGo. Any hint would be appreciated.

kind regards
Sebastian


[1] 
http://docs.opengroupware.org/Members/buzzdee/openbsd/GNUstep%20ports%20for%20OpenBSD/document_view


[2] 
http://docs.opengroupware.org/Members/buzzdee/openbsd/OGo%20ports%20for%20OpenBSD/document_view