No callback after sqlite3_key when using CocoaPods

Hello,

I’m trying to use SQLCipher with CocoaPods. My old project setup was like this:

  • A core-framework (MyCoreFramework)
    • This framework uses the SQLCipher lib
  • An app which uses MyCoreFramework

Now I switched over to CocoaPods and have my current setup as follows:

  • A private pod (MyPrivatePod)
    • This pod uses the SQLCipher CocoaPod
  • An app which uses MyPrivatePod

Before I used CocoaPods my app worked fine with SQLCipher, but since I switched to CocoaPods I couldn’t even run my app once.
It seems like the program hangs on the call to sqlite3_key. I tried debugging with breakpoints and stepping into whatever the program was doing, but I’ve got no clue as to what all the SQLCipher code does.

I don’t know if it’s any helpful, but when stepping into the code I think the last thing I saw was: if( sqlite3GlobalConfig.isInit ) return SQLITE_OK; somewhere in the function void sqlcipher_activate().

My own code looks like:

#define OPEN_DB() sqlite3_open([[self databasePath] UTF8String], &_db)

	//try.
	if(SQLITE_OK != OPEN_DB()) {
		[self closeDatabase];
		[self removeDatabase];
		
		//retry
		OPEN_DB();
	}
	
	// open database
	if (nil == _db) { 
		DLog(@"failed to open Database");
		return NO;
	}

	if(nil != key) {
		// go go crypto, go!
		sqlite3_key(_db, key, (int)strlen(key));
	}

Since the program doesn’t crash somewhere, I don’t know where to start looking.
Could anyone help me out?

Thanks

Hello @gerald

Please make sure your application is defining -DSQLITE_HAS_CODEC, otherwise the keying API is not accessible.

I’ve checked if the flag is present in the build settings. Both the private pod and the app have the -DSQLITE_HAS_CODEC flag set.
Also checked and put the flag into the custom flags for the Swift Compiler (tried it without putting it here first).

Hi @gerald

Since you mentioned that you are using Swift, can you try adding this to your bridging header of your private pod?

#define SQLITE_HAS_CODEC 1
#include "sqlite3.h"

Hi @developernotes

I don’t have a bridging header since my private pod is a framework, should I add your snippet to the umbrella header instead?

Oh and forgot to add but, the code that is using the sqlite3_key is written in Objective-C; as in the call is being made from ObjC.

(Sorry for the late reply, might be the timezone diff)

Hi @gerald,

Have you tried disabling break points so that it crashes? If so, do you have an exception code, e.g. EXC_BAD_ACCESS?

Are there any duplicate symbol warnings in the build log when you try to build and run your app? This could be caused by linking against both libsqlcipher.a (or the framework version) and libsqlite3.dylib.

I’m not very familiar with CocoaPods, so I’m not sure where things are breaking down, but another thing to check is that the sqlte3_* symbols are available to both your app and your framework, and those should be provided by linking both against SQLCipher (and not the system provided library, sqlite3.dyld).

When we include another Xcode project in our main projects, or workspaces, we can get the impression that build settings for the “top-level” projects go “down” to these “sub-projects.” They do not!

Hope that helps. Cheers!

Hi @wgray,

The program never crashes, it just never continues after the call to sqlite3_key.
I’m not aware of any duplicate symbols, my inspector doesn’t say so at least.

I’m going to reinstall everything and afterwards manually link SQLCipher, hoping that fixes something.

I’ll keep you guys posted.

@gerald - I think @wgray is right on this one. We’ve had other reports of similar deadlock behavior when the system SQLite is linked as well as SQLCipher. It is an incompatibility, likely due to conflicting library states. For instance, in the past we’ve seen this with applications that include FMDB. If you are using any other pods it would be important that they do not declare a dependency on the sqlite library.

Which inspector are you referring to, @gerald?

In Xcode, if you type ⌘ 8 the Report navigator should display the most recent Build and Debug logs. Select the build log and look for the Link step for the application target. If there are duplicate symbol issues warnings will appear there where mine is currently showing green (success) for an app I’m working on:

You might also see such warnings under and dependency targets, which would show nearer the top of the Build log.

I was referring to the Xcode issue navigator (⌘4) and the report navigator (⌘8), both do not warn me about any duplicate symbols. Moreover, the link step seems to succeed for me as well.
I do get a lot of warnings about ambiguous expansions and more, but that shouldn’t obstruct the call to sqlite3_key…right?

I’ve added 2 screenshots; 1 with a subset of all the warnings and 1 with the link success (I’ve merged the screenshots in 1 image since I’m unable to upload more then 1 image).

@gerald It’s been a while since I was looking into the issue previously, but IIRC, the problem is that a third party pod would be linked with the system SQLite. Your application could be using SQLCipher proper, and would not have duplicate symbol warnings. However, the end state of the build would result in the deadlock. Can you go through every pod you are using and make sure there are no declared dependencies on sqlite?

@sjlombardo; I will do that, thanks for the suggestion.

I’m on a vacation now, so will get back to the topic in ~1 month.

Hi @sjlombardo,

How do I know for sure if a pod is using SQLit or not?
The pods I’m using right now are:

  • ‘UrbanAirship-iOS-SDK’
  • ‘Google/Analytics’
  • ‘TBXML’

and of course:

  • ‘SQLCipher’

But I assume, excluding ‘SQLCihper’ none of these should use sqlite, right?

@gerald you basically need to look at all the dependencies in each source podspec. In this case, you can see that sqlite3 is a library dependency for both UrbanAirship-iOS-SDK and GoogleAnalytics, :

https://github.com/CocoaPods/Specs/blob/master/Specs/UrbanAirship-iOS-SDK/7.2.2/UrbanAirship-iOS-SDK.podspec.json

https://github.com/CocoaPods/Specs/blob/master/Specs/GoogleAnalytics/3.14.0/GoogleAnalytics.podspec.json

These will cause the system sqlite3 to be linked, causing the problem. You should try to remove UrbanAirship and GoogleAnalytics temporarily to verify the problem is resolved if they are not included.

Hi, sjlombardo and gerald! I have same problem with SQLCipher + YandexMobileMetrica . Without dependency ‘YandexMobileMetrica’ everything works well.

How can I resolve this conflict?

@nullproduction Unfortunately there is not an easy fix in this case. I believe you might need to create local podspecs for any pods that declare a dependency like that, and then modify them to remove the sqlite dependency.

@sjlombardo
(Sorry for the late reply)

Removing GoogleAnalytics and Urban Airship is sadly quite a hassle for me (they’re both quite strongly interwoven in my app), but based on @nullproduction’s answer; I think it would work if I removed the pods.

Still, you said there is no easy fix; modifying the pods locally is quite troublesome. Moreover, removing sqlite3 makes UrbanAirship unusable (the pod won’t build).

Right now I’ve (sort of) given up on creating my own private pod, I just can’t seem to get it to work. But sadly I now get this problem with Xcode 8 and iOS 10 as well. So back to square one…

@gerald Thanks for getting back to me. We’ve been looking into this further. Can you please provide the following information:

  1. From your XCode Target Build Settings, what is the resolved value for your Other Linker Flags setting
  2. What version of CocoaPods you are running (pod --version)
  3. What version of the SQLCipher pod are you using (i.e. from Podfile)
  4. What order did you install the pods? i.e. was Urban Airship installed before SQLCipher, or visa versa?

I’ve no actual build anymore with the setup in my OP. Since I couldn’t get the pod to work, I reverted back to manually adding the library. But I’ll try to answer the questions:

  1. The resolved Other Linker Flags right now is:

    $(inherited) -ObjC -l"GoogleAnalytics" -l"c++" -l"sqlite3" -l"stdc++" -l"z" -framework "AdSupport" -framework "AddressBook" -framework "AirshipKit" -framework "AssetsLibrary" -framework "CoreData" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreMotion" -framework "FirebaseAnalytics" -framework "FirebaseInstanceID" -framework "GGLAnalytics" -framework "GGLCore" -framework "GoogleInterchangeUtilities" -framework "GoogleSymbolUtilities" -framework "GoogleUtilities" -framework "MessageUI" -framework "SSZipArchive" -framework "SafariServices" -framework "StoreKit" -framework "SystemConfiguration" -framework "TBXML"

Hence the missing SQLCipher pod because I reverted my setup, but with that one added the resolved flags would probably include something with SQLCipher as well (i.e. -framework "SQLCipher").

  1. CocoaPods version 1.0.1
  2. I’m not using it right now, but I was using the most recent version (meaning I didn’t specify a specific version in my Podfile)
  3. SQLCipher was installed last

Hope this can help you and others somewhat.

Hello @gerald

Can you provide some details about how you are manually adding the sqlcipher library to make this work?

We’re trying to track down inconsistencies with how sqlite3 is linked when using SQLCipher via pod as well. If you happen to add back the SQLCipher pod in the future, can you capture the resolved Other Linker Flags and update this post?