public
Description: The Nu programming language.
Homepage: http://programming.nu
Clone URL: git://github.com/timburks/nu.git
Memory management error fixed, (NSData datawithShellCommand:), nil in 
containers.

The results of calls to certain functions were being over-retained.
Normally, the results of Nu functions and methods are returned
"autoreleased", or with no additional retains, as this is the
convention for Objective-C methods. In Objective-C, the only exceptions
to this are for alloc, allocWithZone, copy, copyWithZone, mutableCopy,
mutableCopyWithZone, and new. These methods return objects with an
extra retain, and this change set fixes incorrect handling of this
in Nu. When Nu implementations of these methods are called by Objective-C
code, they must return properly retained values. Previously Nu was
doing the right thing but for the wrong methods (init methods).
That caused objects created when Objective-C callers called Nu init
methods to be over-retained and leaked.

A new file of unit tests is included to test memory management.
Because these tests require an Objective-C component, a helper
class was added Nu in objc/testhelper.m.

As a convenience, a new (NSData dataWithShellCommand:) is added and
is similar to (NSString stringWithShellCommand:).

Also, because certain Nu applications were having problems inserting
nil into Cocoa containers (NSDictionary, NSArray, NSSet, and their
mutable variants), these changes reinstate the method-swizzling trick
used to make those containers accept nil and internally convert it
to (NSNull null).
timburks (author)
Sun May 04 22:17:39 -0700 2008
commit  01381604d45343aea5e1454cf20e6043a2fca232
tree    72b1404df4206777c0d0c790a53f3583bb767630
parent  edd334987a9f72f3f4bb2d68a2a1b2c7115297c4
...
1085
1086
1087
1088
 
 
1089
 
1090
1091
1092
...
1108
1109
1110
1111
1112
1113
1114
 
 
 
 
 
 
 
 
1115
1116
1117
...
1085
1086
1087
 
1088
1089
1090
1091
1092
1093
1094
...
1110
1111
1112
 
 
 
 
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
0
@@ -1085,8 +1085,10 @@ static void objc_calling_nu_method_handler(ffi_cif* cif, void* returnvalue, void
0
     //NSLog(@"in nu method handler, putting result %@ in %x with type %s", [result stringValue], (int) returnvalue, ((char **)userdata)[0]);
0
     char *resultType = (((char **)userdata)[0])+1;// skip the first character, it's a flag
0
     set_objc_value_from_nu_value(returnvalue, result, resultType);
0
- if (((char **)userdata)[0][0] == '!')
0
+ if (((char **)userdata)[0][0] == '!') {
0
+ //NSLog(@"retaining result for object %@, count = %d", *(id *)returnvalue, [*(id *)returnvalue retainCount]);
0
         [*((id *)returnvalue) retain];
0
+ }
0
 
0
     [arguments release];
0
 
0
@@ -1108,10 +1110,14 @@ IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature)
0
     const char *methodName = sel_get_name(sel);
0
     #endif
0
     BOOL returnsRetainedResult = NO;
0
- if ((strlen(methodName) >= 4) // retain the result of any method
0
- && !strncmp("init", methodName, 4) // whose name begins with "init"
0
- && strcmp("initialize", methodName) // unless it is named "initialize"
0
- )
0
+
0
+ if ((!strcmp(methodName, "alloc")) ||
0
+ (!strcmp(methodName, "allocWithZone:")) ||
0
+ (!strcmp(methodName, "copy")) ||
0
+ (!strcmp(methodName, "copyWithZone:")) ||
0
+ (!strcmp(methodName, "mutableCopy")) ||
0
+ (!strcmp(methodName, "mutableCopyWithZone:")) ||
0
+ (!strcmp(methodName, "new")))
0
         returnsRetainedResult = YES;
0
     if (returnsRetainedResult)
0
         sprintf(userdata[0], "!%s", return_type_string);
...
424
425
426
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
428
429
...
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
0
@@ -424,6 +424,33 @@ extern id Nu__null;
0
 
0
 @end
0
 
0
+@implementation NSData(Nu)
0
+
0
+#ifndef IPHONE
0
+// Read the output of a shell command into an NSData object and return the object.
0
++ (NSData *) dataWithShellCommand:(NSString *) command
0
+{
0
+ NSTask *task = [NSTask new];
0
+ [task setLaunchPath:@"/bin/sh"];
0
+ #ifdef DARWIN
0
+ NSPipe *input = [NSPipe new];
0
+ [task setStandardInput:input];
0
+ NSPipe *output = [NSPipe new];
0
+ #else
0
+ NSPipe *input = [NSPipe pipe];
0
+ [task setStandardInput:input];
0
+ NSPipe *output = [NSPipe pipe];
0
+ #endif
0
+ [task setStandardOutput:output];
0
+ [task launch];
0
+ [[input fileHandleForWriting] writeData:[command dataUsingEncoding:NSUTF8StringEncoding]];
0
+ [[input fileHandleForWriting] closeFile];
0
+ NSData *data = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile];
0
+ return data;
0
+}
0
+#endif
0
+@end
0
+
0
 @implementation NSNumber(Nu)
0
 
0
 - (id) times:(id) block
...
264
265
266
 
 
 
267
268
269
...
273
274
275
276
 
277
278
279
...
285
286
287
288
 
289
290
291
...
264
265
266
267
268
269
270
271
272
...
276
277
278
 
279
280
281
282
...
288
289
290
 
291
292
293
294
0
@@ -264,6 +264,9 @@ void NuInit()
0
         // Their implementations are identical; this avoids code duplication.
0
         transplant_nu_methods([NSProxy class], [NSObject class]);
0
 
0
+ void nu_swizzleContainerClasses();
0
+ nu_swizzleContainerClasses();
0
+
0
         // Stop NSView from complaining when we retain alloc-ed views.
0
         Class NSView = NSClassFromString(@"NSView");
0
         [NSView exchangeInstanceMethod:@selector(retain) withMethod:@selector(nuRetain)];
0
@@ -273,7 +276,7 @@ void NuInit()
0
         nu_initProtocols();
0
         // if you don't like making Protocol a subclass of NSObject (see nu_initProtocols), you can do this instead.
0
         // transplant_nu_methods([Protocol class], [NSObject class]);
0
-
0
+
0
         #ifndef MININUSH
0
         // Load some standard files
0
         // Warning: since these loads are performed without a context, the non-global symbols defined in them
0
@@ -285,7 +288,7 @@ void NuInit()
0
         [Nu loadNuFile:@"help" fromBundleWithIdentifier:@"nu.programming.framework" withContext:nil];
0
         #endif
0
         #endif
0
-
0
+
0
         #else
0
         [[Nu parser] parseEval:@"(load \"nu\")"];
0
         #endif
...
16
17
18
19
20
21
22
23
...
85
86
87
88
...
16
17
18
 
 
19
20
21
...
83
84
85
 
0
@@ -16,8 +16,6 @@ See the License for the specific language governing permissions and
0
 limitations under the License.
0
 */
0
 
0
-#if 0
0
-// this code is no longer necessary
0
 
0
 #import <Foundation/Foundation.h>
0
 #import "class.h"
0
@@ -85,4 +83,3 @@ void nu_swizzleContainerClasses()
0
     [NSCFSet exchangeInstanceMethod:@selector(addObject:) withMethod:@selector(nuAddObject:)];
0
     [pool release];
0
 }
0
-#endif

Comments

    No one has commented yet.