johnbakers johnbakers - 2 years ago 105
Swift Question

Swift String from C String has correct length but incorrect contents

I'm having a similar issue to this fellow, but the problem is not the same cause as in that answer.

I'm getting a

const char *
from a C function. This function is actually implemented in C++ and it returns a struct by value which contains the return value of
std::string c_str()
which is a C pointer to the string contents. This string lives in static memory. Since the pointer is copied into the return, I would expect the data to be fine.

According to Xcode's debugger, the string I get back is actually the correct length as I'd expect (see
below with correct character count of 7), but the contents are garbage. This is in a UITableView method, and what's very strange is that the garbage problem disappears if I use the
TableView method (which I've wired to a button) which then has valid content for the
variable below. However this subsequent invocation of
does not alter any of the data used elsewhere in the table, only this problematic string garbage goes away.

enter image description here

Here is the debugger on first pass, showing garbage but correct length:

enter image description here

And here is the next pass when the text is correct:

enter image description here

I'm at a loss to understand this behaviour. The struct
contains others properties that are not corrupted when they are returned, but this
char *
is garbage on first pass only, with correct length nonetheless.

I'd appreciate any pointers (no pun intended) on what is happening here.

Update: I have isolated the problem much further, and it is stranger than I thought. A single Swift
function actually solves the issue, which makes no sense. I refactored the code a bit and here are the relevant parts:

For the UITableView cell:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("sceneCell", forIndexPath: indexPath)
let name = sceneNames[indexPath.row]
cell.textLabel?.text = name
cell.detailTextLabel?.text = String(nodeCount(sceneID(sceneIDs[indexPath.row])))

return cell

There is no problem here. I have a button to update the UI, which calls this:

func updateUI(){
let s = getAllScenes()
sceneIDs = convert(Int(s.count), data:
for sid in sceneIDs {
let s = getScene(sid)
let name = String.fromCString(!

Instead of looking up the cell text for each cell individually, I grab them all at once and then lookup in a Swift array.

Here is the interesting part: The code above always works perfectly with no issues.

However, if I remove the line
, the issue discussed at the top of this thread appears and text is garbage, both in the logging and in the actual UI cell.

How could a single line of logging affect this?

Finally, here is the C++ code for the function returning the C string:

scene getScene(sceneID s){
static std::map<sceneID, std::vector<nodeID> > nodeArrays;
auto ss =;
auto sceneroots = ss.roots;
if (nodeArrays.count(s)>0);
else confirmInsertion(nodeArrays.emplace(s, std::vector<nodeID>{}));
auto v =;
for (const auto&i:sceneroots) v.push_back(i);
scene sr;;
return sr;

If I log
it is always correct.

Here is

typedef struct {
const char* name;
arrayID roots;
} scene;

Answer Source

One issue you should observe is this within the C++ function:

Given that this is your scene definition:

typedef struct {
    const char* name;
    arrayID roots;
  } scene;

Inside the getScene C++ function, you're doing this:

auto ss =;

Then you do this later:

  scene sr; =;
  return sr;

The issue is that since ss is a local variable, the pointer assigned to will not be valid when the function returns. Accessing this pointer leads to undefined behavior.

One fix for the problem is to copy the contents of the string to a buffer that is sent by the client program, or copy the contents to a buffer you know is available by the client and won't be invalidated. Since I do not know Swift, you will have to negotiate how to accomplish this.

The other fix is to make sure you are accessing the same std::string, not a copy of the std::string:

auto& ss =;

Now a reference to the scene is returned. But then you have the issue of making sure that the string within the scene is not mutated at all when you actually refer to the returned c_str() value later on in your application. A C++ programmer would not hold onto the return value of c_str() for an extended time, since this can lead to hard-to-diagnose bugs.

The bottom line is that always be suspicious of returning a character pointer as a means of returning string data. The usual way that an API returns string data is to have the client supply a buffer and the API fills the buffer with the string data, or less likely, the API allocates memory and returns a pointer to the allocated memory (which leads to complications as the API has to free the memory by some means to avoid memory leaks).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download