CLANG Pass-By-Value Warning? - objective-c

The following code compiles fine ...
int main (int argc, const char * argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// VARIABLES
MDD *MDD_structure;
NSString *mddFile = #"/Users/Gary/Code/Mdd/xTest.mdd";
NSFileHandle *inFile;
NSData *inBuffer;
int MDD_fCount;
int MDD_vCount;
// OPEN FILE ON DISK
inFile = [NSFileHandle fileHandleForReadingAtPath:mddFile];
if(inFile == nil) NSLog(#"FILE: Open ... ERROR");
else NSLog(#"FILE: Open ... OK");
// READ FRAME COUNT
inBuffer = [inFile readDataOfLength:sizeof(int)];
[inBuffer getBytes:&MDD_fCount length:sizeof(int)];
MDD_fCount = CFSwapInt32BigToHost(MDD_fCount);
NSLog(#"FC: %d", MDD_fCount);
But when I run it through the static analyzer "CLANG LLVM 1.0" I get the following ...
warning: Pass-by-value argument in function call is undefined.
MDD_fCount = CFSwapInt32BigToHost(MDD_fCount);
^ ~~~~~~~~~~
1 diagnostic generated.
Can anyone tell me what I am missing?
gary

You're getting an error because clang isn't convinced that simply passing the address of your variable to a function is the same as giving it a value. You could probably initialize MDD_fCount to 0 to start with to get rid of the error.

It means that you haven't initialized MDD_fCount. See this blog post and this other question for additional info.

Related

Why is this autorelease error occurring with ARC enabled?

I wrote a small CLI program to delete specific Safari cookies for me. Functionally it's fine, but it's throwing up warnings about objects being "autoreleased with no pool in place". My project has ARC enabled, hence why I don't have any autorelease pools.
Here's my code:
// NSLog replacement from http://stackoverflow.com/a/3487392/1376063
void IFPrint (NSString *format, ...) {
va_list args;
va_start(args, format);
fputs([[[NSString alloc] initWithFormat:format arguments:args] UTF8String], stdout);
fputs("\n", stdout);
va_end(args);
}
int main(int argc, const char * argv[])
{
NSString *urlSearchString;
if (argc > 1) {
urlSearchString = [[NSString alloc] initWithUTF8String:argv[1]];
}
else {
IFPrint(#"No URL provided, quitting.");
return 1;
}
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSString *filterString = [[NSString alloc] initWithFormat:#"domain ENDSWITH '%#'", urlSearchString];
NSPredicate *filter = [NSPredicate predicateWithFormat:filterString];
NSArray *matchedCookies = [cookieStorage.cookies filteredArrayUsingPredicate:filter];
for (int i = 0; i < matchedCookies.count; i++) {
[cookieStorage deleteCookie:[matchedCookies objectAtIndex:i]];
}
IFPrint(#"Removed %li cookies", matchedCookies.count);
return 0;
}
The message I get is:
objc[15502]: Object 0x107b2bf00 of class NSThread autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
Which appears in the Xcode debugger or when running the release binary directly (slight digression: shouldn't these messages be stripped out of the "release" build?). The line that causes it seems to be:
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
Similarly, if I run it without passing an argument, I get a similar message:
objc[15630]: Object 0x100114ed0 of class __NSCFString autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
objc[15630]: Object 0x100114f80 of class __NSCFData autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
Which appears to come from the IFPrint function I'm using (however this doesn't show up when I use the IFPrint when I provide a proper argument).
I'm a bit out of my depth here, can anyone show me where (and how) I've gone wrong?
ARC still requires an autorelease pool. Methods like [NSPredicate predicateWithFormat:filterString] continue to release an autoreleased object (though you no longer need to concern yourself all that much since ARC handles it). Furthermore the internal implementation of any library method you call may create arbitrarily many autoreleased objects while running.
You should wrap your code in an autorelease pool via the #autoreleasepool mechanism.
Wrap the entire body of main with #autoreleasepool like so:
int main(int argc, const char * argv[])
{
#autoreleasepool
{
// your code
}
}
All you need to do is add an autoreleasepool in your main.
int main(int argc, const char * argv[])
{
#autoreleasepool
{
//Your code
}
}

CFArrayGetValueAtIndex not returning aything

I have an extremely simple code snippet to get the application support directory of a use. Problem is, it doesn't work! I get the values in a CFArrayRef (because I want to use C code since I will use this snippet in a C++ application later) and try to get the first string in there using CFArrayGetValueAtIndex(). I convert the returned void* to a char* using a C-style cast and attempt to output it using printf(), but nothing gets outputted! Can anyone explain why? I've looked online through the documentation for CFArray and tried to google the issue, but came up with nothing. Any help would be really appreciated!
Code:
#include <Foundation/Foundation.h>
#include <typeinfo>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CFArrayRef array = \
(CFArrayRef)NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory,
NSUserDirectory,
YES);
char* string = (char*)CFArrayGetValueAtIndex(array, 0);
printf("string: %s\n", string);
[pool drain];
}
Why are you converting it to a char*? The resulting array from NSSearchPathForDirectoriesInDomains() contains CFStringRefs, not char*s.
Try using CFShow((CFTypeRef)CFArrayGetValueAtIndex(array, 0));

Weird error NSAssert

I can't figure out why I get
use of undeclared identifier _cmd did you mean rcmd
on the line where NSAssert is.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int x = 10;
NSAssert(x > 11, #"x should be greater than %d", x);
[pool drain];
return 0;
}
Inside every Objective-c method there are two hidden variables id self and SEL _cmd
so
- (void)foo:(id)bar;
is really
void foo(id self, SEL _cmd, id bar) { ... }
and when you call
[someObject foo:#"hello world"]
it is actually
foo( someObject, #selector(foo), #"hello world")
If you cmd-click on NSAssert to jump to it's definition you will see that it is a macro that uses the hidden _cmd variable of the method you are calling it from. This means that if you are not inside an Objective-c method (perhaps you are in 'main'), therefore you don't have a _cmd argument, you cannot use NSAssert.
Instead you can use the alternative NSCAssert.
NSAssert is only meant to be used within Objective-C methods. Since main is a C function, use NSCAssert instead.
Try to replace
NSAssert(x > 11, [NSString stringWithFormat:#"x should be greater than %d", x]);
with
NSCAssert(x > 11, [NSString stringWithFormat:#"x should be greater than %d", x]);
You have to wrap your string in a NSString class if you want to use format parameters. That is because #"" is a default constructor for a plain NSString. The way it is written now gives a third parameter to the NSAssert function and messes with it.
NSAssert(x > 11, [NSString stringWithFormat:#"x should be greater than %d", x]);
TL;DR - stick with stray NSAssert() - don't try this in production
Original code
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int x = 10;
NSAssert(x > 11, #"x should be greater than %d", x);
[pool drain];
return 0;
}
Build failure
Compiling file hello.m ...
hello.m:9:5: error: use of undeclared identifier '_cmd'
NSAssert(x > 11, #"x should be greater than %d", x);
^
/usr/include/Foundation/NSException.h:450:32: note: expanded from macro 'NSAssert'
handleFailureInMethod: _cmd \
^
hello.m:9:5: error: use of undeclared identifier 'self'
/usr/include/Foundation/NSException.h:451:17: note: expanded from macro 'NSAssert'
object: self \
^
2 errors generated.
Based on explanation by #hooleyhoop #Robert and
id
self
SEL,
the following dirty hack may be applicable if I insist on using
NSAssert() instead of
NSCAssert()
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int x = 10;
// Dirty hack
SEL _cmd=NULL;
NSObject *self=NULL;
NSAssert(x > 11, #"x should be greater than %d", x);
[pool drain];
return 0;
}
Build & run
Compiling file hello.m ...
Linking tool hello ...
2021-03-04 21:25:58.035 hello[39049:39049] hello.m:13 Assertion failed in (null)(instance), method (null). x should be greater than 10
./obj/hello: Uncaught exception NSInternalInconsistencyException, reason: hello.m:13 Assertion failed in (null)(instance), method (null). x should be greater than 10
Hooray it works! But, alas, please stay away from it :)

Assignment from incompatible pointer type in my Objective-C code

Yesterday, I copied and compiled the code below and it was fine. But today when I compiled the code it gave me a warning and won't run the .exe. I'm new in Objective-C and I'm using GNUstep on window.
testString.m: In function 'main':
testString.m:5:13: warning: assignment from incompatible pointer type
** testString.m:5:13 it front of (=)
Here's the code.
//testString.m
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSString *testString = [[NSString alloc] init ];
testString = "Here's a test string in testString!";
NSLog(#"testString: %#", testString);
return 0;
}
NSString literals must have # symbol before them:
testString = #"Here's a test string in testString!";
One more problem with your code is that in 1st line you create an instance of NSString which you overwrite in the 2nd line - so it just leaks. Assign value to testString in its declaration directly:
NSString *testString = #"Here's a test string in testString!";

Very basic Objective-C/C Problem

Here's my code:
#import <Foundation/Foundation.h>
void PrintPathInfo() {
const char *path = [#"~" fileSystemRepresentation];
NSLog(#"My home folder is at '%#'", path);
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
PrintPathInfo();
[pool drain];
return 0;
}
And here's my problem:
Program received signal: “EXC_BAD_ACCESS”.
I really think the problem is my NSLog but I don't know how to solve it.
Could someone help me please? Thanks!
path is not an NSString, which is why that crashes. %# in a formatting string expects an object, and asks it for a description to get a string to print... because you are using a C style string, you need to use the standard C string formatters OR convert the const char * back to an NSString using the initWithCString:encoding: class method of NSString.
Staying with a const char *, you can use:
NSLog(#"My home folder is at '%s'", path);
which would work.
%# is for objects. (Like NSString). for const char* you will want the good old %s from the c's printf format codes.
See http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
For the format specifies and their meanings