I have use sqlite in my iOS project for database. In iOS 9 all things are working perfectly. Now i have update new Xcode. But app is crashes many times at 'sqlite3_prepare_v2'.
Also, i am not closing database overtime. And open it only once.
I have added DB open in below code b'acs in debug i got DB close. But still got crash.
crash
Can anyone help me ?
Thanks in advance
I think issue is in line 2592.
Do not treat key as string when passing it to sqlite3_key(...)
Not sure how you generate key but if first byte is set '\0' then strlen return 0
(which may happen pretty often if you use some autogenerated helper based on NSData random bytes)
sqlite3_key definition:
SQLITE_API int SQLITE_STDCALL sqlite3_key(sqlite3 *db, const void *pKey, int nKey)
It expects nKey bytes where "\0" is allowed too
Instead try:
NSData *passBytes = [g_sqlite_key dataUsingEncoding:NSUTF8StringEncoding];
int status = sqlite3_key(contactDB, passBytes.bytes, passBytes.length);
if (status != SQLITE_OK) {
// handle error and return
}
// continue...
Related
For security reasons we need Always to wipe sensitive data from memory.
Usually it is not something that i see done in IOS but for apps and need extended security it is very important.
The Data that Usually needs to be wiped if NSData and NSString objects (pointing to nil does not wipe the data and it is a security breach)
I've managed to wipe my NSStrings with the code below (When password is NSString):
unsigned char *charPass;
if (password != nil) {
charPass = (unsigned char*) CFStringGetCStringPtr((CFStringRef) password, CFStringGetSystemEncoding());
memset(charPass, 0, [password length]);
password = nil;
}
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
When password is NSData It suppose to be even more strait forward and the code bellow suppose to work:
memset([password bytes], 0, [password length]);
But this gives me a compilation error:
No matching function for call to 'memset'
I can't find a workaround to point to the password address and wipe the bytes over there like I did with the string (bytes method should let me do just that from what I understand but it doesn't compile for some reason that I cant figure out)
Any one has an idea for this?
10x
Your string deallocator is fragile. You write:
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
This is documented behaviour as CFString (and hence NSString) does not guarantee you direct access to its internal buffer. You don't say what how you handle this situation, but if you don't erase the memory you presumably have a security problem.
In the case you do get a valid pointer back you are using the wrong byte count. The call [password length] returns:
The number of UTF-16 code units in the receiver.
which is not the same as the number of bytes. However CFStringGetCStringPtr returns:
A pointer to a C string or NULL if the internal storage of theString does not allow this to be returned efficiently.
If you have a C string you can use C library function strlen() to find its length.
To address the case when CFStringGetCStringPtr returns NULL you could create the string yourself as a CFString and supply a custom CFAllocater. You shouldn't need to write a complete allocator yourself, instead you could build one based on the system one. You can get the default allocators CFAllocatorContext which will return you the function pointers the system uses. You can then create a new CFAllocator based of a CFAllocatorContext which is a copy of the default one except you've changed the deallocate and reallocate pointers to functions which you have implemented in terms of the default allocate, reallocate and deallocate but also call memset appropriately to clear out memory.
Once you've done that doing your security wipe comes down to making sure these custom created CFString objects, aka NSString objects, are deallocated before your app quits.
You can find out about CFAllocator, CFAllocatorContext etc. in Memory Management Programming Guide for Core Foundation.
Which brings us to your actual question, how to zero an NSData. Here you are in luck an NSData object is a CFData object, and CFData's CFDataGetBytePtr, unlike CFStringGetCStringPtr, is guaranteed to return a pointer to the actual bytes, straight from the documentation:
This function is guaranteed to return a pointer to a CFData object's internal bytes. CFData, unlike CFString, does not hide its internal storage.
So code following your pattern for CFString will work here. Note that using NSData's bytes is not guaranteed in the documentation to call CFDataGetBytePtr, it could for example call CFDataGetBytes and return a copy of the bytes, use the CFData functions.
HTH
While I cannot speak for the actual safety of doing this, your problem is that NSData's bytes method returns a const void *
https://developer.apple.com/documentation/foundation/nsdata/1410616-bytes?language=objc
You can cast it to a void * if you want by
memset((void *)[password bytes], 0, [password length]);
If you use a NSMutableData, you won't have to do this.
I have what should be a dead-simple piece of code that is failing for me in strange ways.
void MediaShare(char* text, char* furl) {
NSString *status = [NSString stringWithUTF8String: text];
NSString *media = [NSString stringWithUTF8String: furl];
[[SocialShare sharedInstance] mediaShare:status media:media];
text is just a line of text for Twitter sharing, and furl is just a file location string. I am getting a crash down past this function that comes down to bad data getting passed. Putting a breakpoint at the head of this function yields the following-
Image of Xcode variable monitor
The two values look fine, although not sure if the * values that only contain the first char are a problem.
Anyway, jumping to the end, and status and media appear to be converted to hex values.
Converted to hex values?
Any ideas? To give the full story, this is a Unity plug-in. I am simply passing in two strings from Unity C# to this function.
Thanks so much.
The code looks fine so far, if the input values are well formed C char* strings that can be interpreted as an UTF-8 encoded string.
status and media being hex values at the end of the function hint that they are. Both are pointers to Objective-C objects, so this is expected. Print them to the debug console or use po status at the debug console to check their contents (it will print the result of the -description method of status which is the string content in that case).
The subsequent crash might be caused elsewhere in the code.
What's the crash's log output?
My boss is asking me, which PRGN (Pseudo Random Number Generator) is using our iOS App for encrypting and decrypting data.
We are using the native KeyChain services for storing the data and I don't know what to answer since we are using the KeyChainItemWrapper for accessing the single items i.e. password, ports, etc. in our App and there is not too much reference about this.
I already debugged the app to see if I find something but I couldn't find something yet.
Any help would be appreciated,
thanks
If you need random bytes as opposed to a a random number:
randomBytes: returns count random bytes in *bytes, allocated by the caller.
Returns 0 on success or -1 if something went wrong, check errno to find out the real error.
#import <Security/Security.h>
+ (NSData *)randomBytes:(size_t)count
{
NSMutableData *data = [NSMutableData dataWithLength:count];
SecRandomCopyBytes( kSecRandomDefault,
data.length,
data.mutableBytes);
return data;
}
Be sure to add the Security framework.
I'm facing a problem in this code: it's working ok on iPhone and iPad Mini, but it's giving the error message on the big iPad. Is there any reason?
Code:
- (sqlite3_stmt *)executeQuery:(char *)aQuery {
NSString *dbPath = [[NSUserDefaults standardUserDefaults] objectForKey:kDBPath];
sqlite3_stmt *statement = NULL;
sqlite3 *database;
if (sqlite3_open((char *)[dbPath UTF8String], &database) == SQLITE_OK) {
if (sqlite3_prepare_v2(database, aQuery, -1, &statement, NULL) != SQLITE_OK) {
//Here is the point: on iPad Mini and iPhone it works fine, but on the normal iPad it can't execute this query
NSLog(#"Error on SQL - (sqlite3_stmt *)executeWithReturn:(char *)aQuery");
statement = NULL;
}
} else {
NSLog(#"Error on Open database");
}
return statement;
}
Prints from LLDB:
(lldb) print (BOOL)[[NSFileManager defaultManager] isWritableFileAtPath:dbPath]
(BOOL) $0 = YES
(lldb) print (char *)aQuery
(char *) $1 = 0x1f0a1000 "select CodAplicacao, CodLocalidade, Nome, Desc, DataCriacao, Editando from Aplicacao_en"
Any ideas?
Regards!
EDIT:
It's getting the error "database disk image is malformed". I couldn't find in the internet how to fix it.
In your revised question, you inform us that sqlite3_errmsg is reporting "database disk image is malformed". This is a sign that your database has been corrupted. This can happen if your app crashed while doing some database operation at some previous date.
You can confirm this by running the following SQL:
PRAGMA integrity_check;
If you want to go through that process, you can copy the database from your device back to your Mac (using Xcode's Organizer and go to the "Devices" section) and then use your Mac SQLite database tool of choice (worst case, the command line sqlite3 program) and then run the previous PRAGMA command. You can even perform this programmatically (it returns a result set like a SELECT statement).
Thing is, we're fairly confident that it's going to report problems. The easy fix is to rebuild the database (e.g. delete the database and if you originally copied it from the bundle, do that again, if you programmatically created it, repeat that process).
If you're determined to try to recover user data from the database, you can contemplate following the process outlined in Sergei Dorogin's technical blog - SQLiteException "database disk image is malformed". He wrote that for a different platform, but the basic process is probably applicable here. Thing is, that unless you absolutely need to recover user data, that process is probably unnecessary.
So, in short, your database on that device is corrupted and you need to rebuild it. Just delete the app (in case your database is in the Documents folder, you need to delete app to empty out that folder) and reinstall the app and you should be good.
Change your log statement from:
NSLog(#"Error on SQL - (sqlite3_stmt *)executeWithReturn:(char *)aQuery");
to
NSLog(#"Error on SQL - %s: %s", __FUNCTION__, sqlite3_errmsg(database));
That should give you an informative error message that tells you what's wrong.
Generally, these sorts of problems result from version of the database on that particular device. It is extremely unlikely to be related to the device itself.
Perhaps your app created a blank database at some point and thus the table is not found. If you use Xcode's Organizer, go to the "Devices" section, and you can copy the app folders to your Mac and then examine the database on your Mac and see if you confirm that the database is as you expected it to be.
What's the best way to look up the meaning of OSStatus errors ( i.e. -43 ) in Core Audio? Is there a way to process them in your iOS code so they can be formatted to show up with a brief explanation in the console?
After a quick look around, the best way so far seems to be to use the Unix command line tool - macerror - and type in the error code as an argument: not sure if it's possible to call & get the results of a macerror query from my Obj-C code in iOS into a console print out.
A recent article in IOS Dev Weekly linked to a great webpage that allows you to search for all OSStatus codes. Definitely worth bookmarking.
A bit late to the party, but I just noticed that at least one error code (560226676) is actual a four-letter code; it can be represented as '!dat' in big-endian. Searching for that gives kAudioDeviceUnsupportedFormatError.
IOW, it can't hurt to print error codes with a little function like this:
char *OSTStr( OSType type )
{
static union OSTStr {
uint32_t four;
char str[5];
} ltype;
ltype.four = EndianU32_BtoN(type);
ltype.str[4] = '\0';
return ltype.str;
}