bugGNUstep - Bugs: bug #23727, NSDictionary with keys of...

Group
 
 

bug #23727: NSDictionary with keys of different classes

Submitter:  Tamas Mahr <ujpi>
Submitted:  Fri 27 Jun 2008 01:01:44 PM UTC
   
 
Category:  Base/Foundation Severity:  3 - Normal
Item Group:  None Status:  Fixed
Privacy:  Public Assigned to:  None
Open/Closed:  Closed
* Mandatory Fields

Add a New Comment Rich Markup
   

Fri 27 Jun 2008 03:11:17 PM UTC, comment #2: 

Thank you for the quick reply!

About question 2:
I have configured and compiled gnustep-make and gnustep-base using the --enable-native-objc-exceptions. The @try{}@catch{} blocks do catch exceptions, except if it is raised after a forwardInvocation call.

I have also tried to use the NS_DURING, NS_HANDLER, and NS_ENDHANDLER macros, with the same results. I think that native exception handling works for me in the normal way, only not through a forwardInvocation call. Could this be related to the ffcall library?

my compiler:
gcc (GCC) 4.1.2 20070626 (Red Hat 4.1.2-13)
Copyright (C) 2006 Free Software Foundation, Inc.

gnustep-base-1.14.1 and gnustep-make-2.0.2 is compiled from source.

To justify that it works the following program correctly catches the exception I raise, but fails to catch the execption comming from the NSDictionary object.

 #include <Foundation/Foundation.h>

int main(){
  CREATE_AUTORELEASE_POOL(pool);

  NSString *key1 = @"one";
  NSNumber *key2 = [NSNumber numberWithInt: 2];

  NSString *value1 = @"firstValue";
  NSString *value2 = @"secondValue";

  NSMutableDictionary *dict = [NSMutableDictionary dictionary];

  [dict setObject: value1 forKey: key1];
  [dict setObject: value2 forKey: key2];

  @try {
    [NSException raise: @"TestException"
format: @"Just testing"];
  }@catch(NSException *e){
    NSLog(@"%@", e);
  }
 
  @try {
    NSLog(@"dictionary: %@", dict);
  }@catch (NSException *e){
    NSLog(@"%@", e);
  }

  [pool release];
  return 0;
}

Tamas Mahr <ujpi>
Fri 27 Jun 2008 02:16:28 PM UTC, comment #1: 

1. We are trying to duplicate MacOS-X behavior ... this used to be to sort dictionary keys if they all responded to compare:, but has changed to be to sort if they are all strings.
I've changed the code in svn to match the new MacOS-X behavior ... which should fix your problem with the dictionaries.

PS. keys need to support -hash and -copy as well as -isEqual:

2. You are using the new try/catch features of the compiler.  This won't work unless you built gnustep with support for that enabled.  You should use the standard NS_DURING ... NS_HANDLER ... NS_ENDHANDLER macros (see NSException.h) if you want to catch exceptions.
Alternatively, you can configure gnustep-make with --enable-native-objc-exceptions and then rebuild everything.  Don't ask me why language level exceptions are not enabled by default ... I don't really know, perhaps it's to encourage people to write code using the macros so the code will work with older compilers.


Richard Frith-Macdonald <CaS>
Group Member
Fri 27 Jun 2008 01:01:44 PM UTC, original submission:  

Hi all,

I have two issues, and I am not sure that either of them is a bug, but at least the documentation is not clear.

The first is about the keys used in an NSDictionary. As far as I understand the documentation of NSDictionary, I should be able to use keys that are instances of different classes (say an NSString and an NSNumber key). The only requirement that is implicit in the doc is that -isEqual should recognize the object. If I try to use such keys, it works fine as long as I do not want to print the dictionary. The functions converting the dictionary to string die, because one of them calls -compare on two keys, which does not exist for different classes. Now, either it should be forbidden (strongly and explicitely discouraged) to use keys of different types, or it should be required that a -compare method exists, or the conversion functions should not try to compare.

Here is the code reproducing the error:
#include <Foundation/Foundation.h>

int main(){
  CREATE_AUTORELEASE_POOL(pool);

  NSString *key1 = @"one";
  NSNumber *key2 = [NSNumber numberWithInt: 2];

  NSString *value1 = @"firstValue";
  NSString *value2 = @"secondValue";

  NSMutableDictionary *dict = [NSMutableDictionary dictionary];

  [dict setObject: value1 forKey: key1];
  [dict setObject: value2 forKey: key2];

  @try {
    NSLog(@"dictionary: %@", dict);
  }@catch (NSException *e){
    NSLog(@"%@", e);
  }

  [pool release];
  return 0;
}


And here is the backtrace from gdb:

(gdb) r
Starting program: /home/mahr/src/NSDictionaryTest/obj/printTest
[Thread debugging using libthread_db enabled]
[New Thread -1208538384 (LWP 4627)]

Program received signal SIGABRT, Aborted.
[Switching to Thread -1208538384 (LWP 4627)]
0x00296402 in __kernel_vsyscall ()
(gdb) bt
#0  0x00296402 in __kernel_vsyscall ()
#1  0x00129ba0 in raise () from /lib/libc.so.6
#2  0x0012b4b1 in abort () from /lib/libc.so.6
#3  0x0071d71f in objc_exception_throw () from /usr/lib/libobjc.so.1
#4  0x008690f1 in -[NSException raise] (self=0xa09be80, _cmd=0xb2e6b8) at NSException.m:806
#5  0x00868c3a in +[NSException raise:format:arguments:] (self=0xb2e160, _cmd=0xb2e6a0, name=0xb2dedc, format=0xb3fa8c, argList=0xbfba668c "^ͳ")
    at NSException.m:753
#6  0x00868b72 in +[NSException raise:format:] (self=0xb2e160, _cmd=0xb40450, name=0xb2dedc, format=0xb3fa8c) at NSException.m:739
#7  0x008a70c1 in -[NSObject doesNotRecognizeSelector:] (self=0x9ffb240, _cmd=0xb40548, aSelector=0xb14288) at NSObject.m:1672
#8  0x008a729d in -[NSObject forwardInvocation:] (self=0x9ffb240, _cmd=0x9fcaf90, anInvocation=0xa09b300) at NSObject.m:1700
#9  0x0094a186 in GSInvocationCallback (callback_data=0xb834f0, args=0xbfba6814) at GSFFCallInvocation.m:975
#10 0x00e31815 in __vacall_r () from /usr/lib/libcallback.so.0
#11 0x00b834f0 in returnTypeInfo () from /usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14
#12 0xbfba6814 in ?? ()
#13 0x00000004 in ?? ()
#14 0xbfba6848 in ?? ()
#15 0x00000000 in ?? ()
(gdb) up
#1  0x00129ba0 in raise () from /lib/libc.so.6
(gdb)
#2  0x0012b4b1 in abort () from /lib/libc.so.6
(gdb)
#3  0x0071d71f in objc_exception_throw () from /usr/lib/libobjc.so.1
(gdb)
#4  0x008690f1 in -[NSException raise] (self=0xa09be80, _cmd=0xb2e6b8) at NSException.m:806
806       @throw self;
(gdb)
#5  0x00868c3a in +[NSException raise:format:arguments:] (self=0xb2e160, _cmd=0xb2e6a0, name=0xb2dedc, format=0xb3fa8c, argList=0xbfba668c "^ͳ")
    at NSException.m:753
753       [except raise];
(gdb) po except
<NSException: 0xa09be80> NAME:NSInvalidArgumentException REASON:GSCachedInt(instance) does not recognize length INFO:{GSStackTraceKey = "  0: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x12f1e6) +[GSStackTrace currentStack]  /home/mahr/src/gnustep-base-1.14.1/Source/NSException.m: 511
  1: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x1300c9) -[NSException raise]  /home/mahr/src/gnustep-base-1.14.1/Source/NSException.m: 801
  2: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x12fc3a) +[NSException raise:format:arguments:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSException.m: 754
  3: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x12fb72) +[NSException raise:format:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSException.m: 742
  4: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x16e0c1) -[NSObject doesNotRecognizeSelector:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSObject.m: 1677
  5: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x16e29d) -[NSObject forwardInvocation:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSObject.m: 1702
  6: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x211186) GSInvocationCallback  /home/mahr/src/gnustep-base-1.14.1/Source/GSFFCallInvocation.m: 978
  7: (/usr/lib/libcallback.so.0: 0x815) __vacall_r  (nil): 0
  8: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0xad3d0) compare_c  /home/mahr/src/gnustep-base-1.14.1/Source/GSString.m: 1200
  9: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0xad22e) -[GSCString compare:options:range:]  /home/mahr/src/gnustep-base-1.14.1/Source/GSString.m: 2821
 10: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x1c0700) -[NSString compare:options:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSString.m: 1755
 11: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x1c0668) -[NSString compare:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSString.m: 1741
 12: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x19587a) OAppend  /home/mahr/src/gnustep-base-1.14.1/Source/NSPropertyList.m: 2244
 13: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x1969ff) GSPropertyListMake  /home/mahr/src/gnustep-base-1.14.1/Source/NSPropertyList.m: 2506
 14: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x1269c4) -[NSDictionary descriptionWithLocale:indent:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSDictionary.m: 1056
 15: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x126958) -[NSDictionary descriptionWithLocale:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSDictionary.m: 1037
 16: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x964c8) GSPrivateFormat  /home/mahr/src/gnustep-base-1.14.1/Source/GSFormat.m: 1862
 17: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0xab785) -[GSPlaceholderString initWithFormat:locale:arguments:]  /home/mahr/src/gnustep-base-1.14.1/Source/GSString.m: 717
 18: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x1bbdd8) -[NSString initWithFormat:arguments:]  /home/mahr/src/gnustep-base-1.14.1/Source/NSString.m: 1051
 19: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x214b4d) +[NSString(GSCategories) stringWithFormat:arguments:]  /home/mahr/src/gnustep-base-1.14.1/Source/Additions/GSCategories.m: 1100
 20: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x15a02e) NSLogv  /home/mahr/src/gnustep-base-1.14.1/Source/NSLog.m: 346
 21: (/usr/GNUstep/System/Library/Libraries/libgnustep-base.so.1.14: 0x159c27) NSLog  /home/mahr/src/gnustep-base-1.14.1/Source/NSLog.m: 255
 22: (/home/mahr/src/NSDictionaryTest/obj/printTest: 0x8048925) main  /home/mahr/src/NSDictionaryTest/printTest.m: 18
 23: (/lib/libc.so.6: 0x116dec) __libc_start_main  (nil): 0
 24: (/home/mahr/src/NSDictionaryTest/obj/printTest: 0x8048711) _start  (nil): 0
"; }
(gdb)

My second question relates to the exception in the previous example.

As you can see, the NSInvalidExecption is not catched by the @try{}@catch{} blocks. I suspect here the forwarding mechanism. I  use the forwardInvocation mechnism in my project and I think I can see the tendency that exceptions are not caught once the call-chain includes a forwardInvocation: call. Can somebody please explain it to me why is that?

Thank You!
Tamas

Tamas Mahr <ujpi>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by CaS (Posted a comment)
  • -email is unavailable- added by ujpi (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2008-06-27 CaS StatusNone Fixed
        Open/ClosedOpen Closed

    Back to the top

    Powered by Savane 3.13-d3ae.
    Corresponding source code