src/sqlite.ios.js
function toCharPtr(str) {
    const objcStr = NSString.stringWithString(str);
    const bufferSize = strlen(objcStr.UTF8String) + 1;
    const buffer = interop.alloc(bufferSize);

    objcStr.getCStringMaxLengthEncoding(buffer, bufferSize, NSUTF8StringEncoding);

    return buffer;
}
function toCharPtr(str) {
    const objcStr = NSString.stringWithString(str);
    const bufferSize = strlen(objcStr.UTF8String) + 1;
    const buffer = interop.alloc(bufferSize);

    objcStr.getCStringMaxLengthEncoding(buffer, bufferSize, NSUTF8StringEncoding);

    return buffer;
}
*
Converts a string to a UTF-8 char array and wraps it in an adopted pointer
(which is GC managed and kept alive until it's referenced by a variable).
The reason for doing it is that iOS runtime marshals JS string arguments via
temporary buffers which are deallocated immediately after the call returns. In
some cases however, we need them to stay alive for subsequent native calls
because otherwise attempts to read the freed memory may lead to unpredictable
app crashes.
E.g. `sqlite3_step` function happens to use the stored `char *` passed as
`dbname` to `sqlite3_open_v2`.
@param str
@returns {AdoptedPointer} object