(compiler) bug in String.withCString?

I have a protocol MetadataValue, that various types conform to. In particular, String conforms to MetadataValue. I am trying to pass a pointer to the string down to C/C++, using a C union, declared in a bridging header:

// bridging header has this:
typedef union CUnionValue {
    bool b;
    int64_t i;
    double d;
    char const* s;
} CUnionValue;

If I write this:

func handleStringCase(value: MetadataValue) {
  let s = value as! String
  s.withCString {
      let union_value = CUnionValue(s: $0)
      someCxxFunction(union_value)
  }
}

then when someCxxFunction prints out the value of the member s, it works fine and we see the contents of whatever was in value, which was really a String.

However, if I write this, it doesn't work:

   func handleStringCase(value: MetadataValue) {
      (value as! String).withCString {
          let union_value = CUnionValue(s: $0)
          someCxxFunction(union_value)
      }
  }

in the sense that when printed out, it's just crap, and not a valid string at all.

What's the difference? Oddly, I can get the second case to work if I pass $0 directly to a C/C++ function that doesn't even do anything, even after the call to someCxxFunction (but within the closure given to withCString). I infer the compiler is making some judgements about lifetimes or something somewhere, but maybe I'm doing something illegal...

I'm using Swift 4.2, not on 5 yet.

1 Like

What's the purpose of having a parameter of MetadataValue, if any value other than String crashes? It's deceptive.

That definitely looks like a compiler or stdlib bug to me; the C string should be valid until the end of the closure, and the cast inside the expression should not be treated differently from the cast outside the expression. We're getting at least one of those things wrong!

Alex, it’s a pared down example. MetadataValue can be one of a number of types. In this case, I’ve already tested outside the function, I know it’s a string, and I’m passing it to handleStringCase. (This is not what I really do, I simplified it to explain what’s going on. THe important part is whether or not we cast into a variable, or an expression, for the call to withCString.

Oh I see. I just missed the purpose here, I didn't pick up that this was a minimal example.

Terms of Service

Privacy Policy

Cookie Policy