Getting a string allocated in a C function via char** parameter?

I still have a very hard time working with C. In this case, I’d like to call a SQLite function that sometimes allocates an error string internally and passes it back via char** parameter:

int sqlite3_exec(
  sqlite3*,                                  /* An open database */
  const char *sql,                           /* SQL to be evaluated */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 1st argument to callback */
  char **errmsg                              /* Error msg written here */

sqlite3_exec(_: OpaquePointer!,
	_ sql: UnsafePointer<Int8>!,
	_ callback: (@convention(c) (UnsafeMutableRawPointer?,
								UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?) -> Int32)!,
	_: UnsafeMutableRawPointer!,
	_ errmsg: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!) -> Int32

This string is freed with a call to void sqlite3_free(void*);

How can I get this as a Swift String?

Also, Xcode 12.3 gives this helpful diagnostic (obviously that code won’t work, was just experimenting and noticed the diagnostic):

errMsg wants to be a place where sqlite3_exec can write back a pointer.

func exec(sql inSQL: String) throws
  var errMsg: UnsafeMutablePointer<Int8>? = nil
  let result = sqlite3_exec(nil, inSQL, nil, nil, &errMsg)
  if result != 0
    let message ={ String(cString: UnsafeRawPointer($0).assumingMemoryBound(to: UInt8.self)) }) ?? ""
    // call sqlite3_free here
    try throwIfNotOK(result, message)

Unfortunately Int8 is not particularly comfortable to work with for strings, but there you are.

1 Like

Wow. I could’ve sworn that was the first thing I tried, but maybe not. Thanks!

Using withMemoryRebound would be better; the earlier is probably fine for this particular case, but isn't the general solution.

let message = { chars -> String in
  let count = strlen(chars)
  let message = chars.withMemoryRebound(to: UInt8.self, capacity: count) { String(cString: $0) }
  return message
Terms of Service

Privacy Policy

Cookie Policy