I'm facing a weird problem. I'm developing an iOS command line barcode scanner utility using libzbar (yes, this is for jailbroken devices). All goes fine except when I'm trying to use the CGImageCreateWithPNGDataProvider()
or CGImageCreateWithJPEGDataProvider()
methods to obtain a CGImageRef
from a file - because these two functions throw a segfault on my 5.1.1 iPad. The problem is not in my custom class, ZBarScanner
, because if I use an UIImage to obtain the image data, using something like
UIImage *uiImage = [UIImage imageWithContentsOfFile:fname];
CGImageRef image = uiImage.CGImage;
then it works fine and prints the data stored in the barcode. Also, the PNG and JPEG images are well-formatted - I can view them using a file browser on the device itself and I tried several other images as well. I even tried to omit all the CFRelease()
function calls and release
messages in order to avoid having dangling pointers. Here's my code:
#define LOG() NSLog(@"Reached line %d", __LINE__)
int main(int argc, char **argv)
{
if (argc != 2)
return 1;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
LOG(); // line 21
NSString *fname = [[NSString stringWithUTF8String:argv[1]] retain]; // added an extra retain just in case
LOG(); // line 25
CFDataRef data = (CFDataRef)[NSData dataWithContentsOfFile:fname];
CGDataProviderRef dProv = CGDataProviderCreateWithCFData(data);
// I also tried using
// dProv = CGDataProviderCreateWithFilename(argv[1]);
// that made no difference either. The data and data provider are
// valid, but the CGImage constructors always segfault.
if (dProv == NULL) {
fprintf(stderr, "Invalid CGDataProvider\n");
abort();
}
LOG(); // line 34
CGImageRef image = NULL;
if ([[fname pathExtension] isEqualToString:@"png"]) {
LOG(); // line 39
NSLog(@"Function pointer: %p", CGImageCreateWithPNGDataProvider);
image = CGImageCreateWithPNGDataProvider(dProv, NULL, false, kCGRenderingIntentDefault); // This function segfaults, or...
LOG();
} else if ([[fname pathExtension] isEqualToString:@"jpg"]
|| [[fname pathExtension] isEqualToString:@"jpeg"]) {
LOG();
image = CGImageCreateWithJPEGDataProvider(dProv, NULL, true, kCGRenderingIntentDefault); // ... or this one.
LOG();
} else {
fprintf(stderr, "File '%s' is neither a PNG nor a JPEG file!\n", argv[1]);
LOG();
abort();
}
LOG();
// CFRelease(dProv);
LOG();
ZBarScanner *scanner = [ZBarScanner zbarScannerWithCGImage:image];
// CFRelease(image);
LOG();
NSArray *arr = [scanner scan];
NSLog(@"The result of the scanning is:\n%@", arr);
LOG();
[pool drain];
return 0;
}
If I run it in the debugger (GDB and NSLog clutter removed for clarity):
gdb ./scanner
(gdb) run ./barcode1.png
Reached line 21
Reached line 25
Reached line 34
Reached line 39
Function pointer: 0x37c5b535
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000000
0x00000000 in ?? ()
(gdb) backtrace
#0 0x00000000 in ?? ()
(gdb)
So even the backtrace doesn't show anything obviously wrong/helpful... It seems though that something is NULL somewhere. I even suspected that due to my toolchain being an unofficial 4.0-based build, these functions might not be available in iOS 5.1.1, so the build succeeds as the CGImageCreateWith[...]DataProvider
symbols are inside the development sysroot but not among iOS' actual dynamic libraries, but if this was the case, the function pointer I NSLogged out would be NULL
, right? However, neither of the NS and CG objects nor the functions seem to be NULL - the only NULL I pass to the CGImage constructors is a decodeArray
parameter, but it's explicitly mentioned in Apple's documentation that it can be NULL... (Update: I tried passing a valid non-NULL array to find out if the documentation is wrong, but I still got the same error).
Could you please give me any pointers (pun intended) about this crash? What am I missing here? All tutorials and references I have found so far suggest using CGDataProvider and CGImage just like this.
data
is a valid object (and non-empty)? Also, have you tried passing some dummy value for the decode array, just to see if the docs are wrong? – Gwenngwennethassert(data != NULL);
andassert([data length] > 0;
and it went through it... – Lissiegcc -g
to generate debug symbols... – LissieCGContext
active at that point. – NurtureCGContext
was my next thought too, but if theCGImageCreateWith[...]DataProvider()
functions required one, it'd be part of the interface (i.e., passed in). Your suspicions about linking problems seem reasonable -- could there be an internal function that the image creation functions use that has been changed from 4.0 to 5.1? I don't know how to find that out. – Gwenngwenneth