[Openmcl-devel] Initialized NSAttributedString printed as [uninitialized]

Paul Krueger plkrueger at comcast.net
Tue Mar 8 13:28:39 PST 2016

I’m not sure if this qualifies as a bug in the objc bridge code or just a minor annoyance.

In Clozure Common Lisp Version 1.10-dev-r16162-trunk  (DarwinX8664) I can do the following:

? (#/initWithString: (#/alloc ns:ns-attributed-string) #@"sss")
#<NS-ATTRIBUTED-STRING [uninitialized] (#x3BC8DCC0)>   <== Note it is called uninitialized
? (#/string *)
#<NS-CONSTANT-STRING "sss" (#x2DA692A0)>
? (inspect **)
#<NINSPECTOR-WINDOW-CONTROLLER <NinspectorWindowController: 0x3bce5770> (#x3BCE5770)>
(inspector window attached as pdf below).

The bug is that CCL prints out the resulting ns:ns-attributed-string object with an “[uninitialized]” tag when it really is initialized properly and works fine.

After a lot of investigation, what is going on is that the alloc method (not init) for NSAttributedString class sets the isa field (normally a pointer to the object’s class) to be a pointer to an INSTANCE of an undocumented private class called NSConcreteAttributedString. If you call (#/class ) on the NSAttributedString instance that is created, you will get that NSConcreteAttributedString instance. Presumably that object either contains or points to the various data that is nominally part of a NSAttributedString instance. All NSAttributedString methods presumably reference internal data indirectly through that isa link. I’m not sure why they chose to use this rather bizarre technique. Maybe that’s just the way the Core Foundation counterpart was defined and they wanted to keep them interchangeable.

The reason that CCL considers this object to be uninitialized can be found in the function initialized-nsobject-p, located in objc-support.lisp. If I’m reading the code correctly, it looks at whether bits beyond the isa link in the malloc’ed space for the instance are all zero and if so declares it uninitialized. For whatever reason the NSAttributedString alloc seems to malloc space after the isa pointer, but doesn’t ever use it, so initialized-nsobject-p thinks it is uninitialized. 

So basically the implementation of NSAttributedString tricks the CCL bridge code into thinking that it is uninitialized. I have no idea whether there are other classes that would trick it similarly, but where there is one, there are likely others.

I spent some time considering how initialized-nsobject-p might be made smarter about this situation. I initially thought that maybe it could check to see if the isa link points to something other than the object’s class as determined from the object macptr and if so declare it to be initialized, but that won’t work correctly because as noted above, the isa link is set as part of the alloc rather than the init so such a test would pass an alloc’ed object that was still uninitialized.

I next considered whether you could look for an isa pointer that pointed to an instance object rather than a class object and then recursively check whether that instance is initialized. That sort of works, but unfortunately the NSConcreteAttributedString that is pointed to is semi-initialized as soon as it is created by the alloc method. That is, there are some non-zero bytes within its structure even before you run any of the NSAttributedString init methods. So calling initialized-nsobject-p on that pointer returns t. That seems like the best of bad alternatives to me, but I’m not sure what the consequences of that might be in other bridge code.

I suppose you could special case things for this class only and check for a non-nil (#/string ), but that doesn’t seem like a good generic solution to the problem unless this is the only class to do this.

Other than costing me some time trying to track down why objects I was creating were seemingly uninitialized, this has only been a nuisance. And now that I’m aware of it, it shouldn't cause me much pain. But if someone thinks it's worthwhile, I’ll file a bug report and let someone else decide how to resolve it.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: Inspect: #<NS-ATTRIBUTED-STRING [uninitialized] (#x3BC8DCC0)>.pdf
Type: application/pdf
Size: 34240 bytes
Desc: not available
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20160308/df09ac5f/attachment.pdf>

More information about the Openmcl-devel mailing list