Freeglut doesn't initialize when using it from Swift - swift

I've tried to use the Freeglut library in a Swift 4 Project. When the
void glutInit(int *argcp, char **argv);
function is shifted to Swift, its declaration is
func glutInit(_ pargc: UnsafeMutablePointer<Int32>!, _ argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!)
Since I don't need the real arguments from the command line I want to make up the two arguments. I tried to define **argv in the Bridging-Header.h file
#include <OpenGL/gl.h>
#include <GL/glut.h>
char ** argv[1] = {"t"};
and use them in main.swift
func main() {
var argcp: Int32 = 1
glutInit(&argcp, argv!) // EXC_BAD_ACCESS
glutInitDisplayMode(UInt32(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH));
glutCreateWindow("my project")
glutDisplayFunc(display)
initOpenGL()
glutMainLoop()
but with that I get Thread 1: EXC_BAD_ACCESS (code=1, address=0x74) at the line with glutInit().
How can I initialize glut properly? How can I get an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>! so that it works?

The reason the right code in C char * argv[1] = {"t"}; does not work is because Swift imports fixed size C-array as a tuple, not a pointer to the first element.
But your char ** argv[1] = {"t"}; is completely wrong. Each Element of argv needs to be char **, but you assign char * ("t"). Xcode must have shown you a warning at first build:
warning: incompatible pointer types initializing 'char **' with an expression of type 'char [2]'
You should better take incompatible pointer types warning as error, unless you know what you are doing completely.
Generally, you should better not write some codes generating actual code/data like char * argv[1] = {"t"}; in a header file.
You can try it with Swift code.
As you know, when you want to pass a pointer to single element T, you declare a var of type T and pass &varName to the function you call.
As argcp in your code.
As well, when you want to pass a pointer to multiple element T, you declare a var of type [T] (Array<T>) and pass &arrName to the function you call.
(Ignoring immutable case to simplify.)
The parameter argv matches this case, where T == UnsafeMutablePointer<Int8>?.
So declare a var of type [UnsafeMutablePointer<Int8>?].
func main() {
var argc: Int32 = 1
var argv: [UnsafeMutablePointer<Int8>?] = [
strdup("t")
]
defer { argv.forEach{free($0)} }
glutInit(&argc, &argv)
//...
}
But I wonder if you really want to pass something to glutInit().
You can try something like this:
func main() {
var argc: Int32 = 0 //<- 0
glutInit(&argc, nil)
//...
}
I'm not sure if freeglut accept this, but you can find some articles on the web saying that this works in some implementation of Glut.

Related

Is Swift's handling of CVarArg for String buggy?

While writing a Swift wrapper for a C wrapper of a C++ library, I've stumbled on some weird bugs regarding Swift's CVarArg. The C wrapper I already have uses variadic functions which I converted to functions using va_list as an argument so they could be imported (since Swift cannot import C variadic functions). When passing arguments to such a function, once bridged to Swift, it uses the private _cVarArgEncoding property of types conforming to CVarArg to "encode" the values which are then sent as a pointer to the C function. It seems however that this encoding is faulty for Swift Strings.
To demonstrate, I've created the following package:
Package.swift
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "CVarArgTest",
products: [
.executable(
name: "CVarArgTest",
targets: ["CVarArgTest"]),
],
targets: [
.target(
name: "CLib"),
.target(
name: "CVarArgTest",
dependencies: ["CLib"])
]
)
CLib
CTest.h
#ifndef CTest_h
#define CTest_h
#include <stdio.h>
/// Prints out the strings provided in args
/// #param num The number of strings in `args`
/// #param args A `va_list` of strings
void test_va_arg_str(int num, va_list args);
/// Prints out the integers provided in args
/// #param num The number of integers in `args`
/// #param args A `va_list` of integers
void test_va_arg_int(int num, va_list args);
/// Just prints the string
/// #param str The string
void test_str_print(const char * str);
#endif /* CTest_h */
CTest.c
#include "CTest.h"
#include <stdarg.h>
void test_va_arg_str(int num, va_list args)
{
printf("Printing %i strings...\n", num);
for (int i = 0; i < num; i++) {
const char * str = va_arg(args, const char *);
puts(str);
}
}
void test_va_arg_int(int num, va_list args)
{
printf("Printing %i integers...\n", num);
for (int i = 0; i < num; i++) {
int foo = va_arg(args, int);
printf("%i\n", foo);
}
}
void test_str_print(const char * str)
{
puts(str);
}
main.swift
import Foundation
import CLib
// The literal String is perfectly bridged to the CChar pointer expected by the function
test_str_print("Hello, World!")
// Prints the integers as expected
let argsInt: [CVarArg] = [123, 456, 789]
withVaList(argsInt) { listPtr in
test_va_arg_int(Int32(argsInt.count), listPtr)
}
// ERROR: Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
let argsStr: [CVarArg] = ["Test", "Testing", "The test"]
withVaList(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
The package is available here as well.
As commented in the code above, printing a String via C or a va_list containing Ints works as expected, but when converted to const char *, there's an exception (EXC_BAD_ACCESS (code=EXC_I386_GPFLT)).
So, in short: did I mess up the C side of it or is Swift doing something wrong here? I've tested this in Xcode 11.5 and 12.0b2. If it's a bug, I'll be happy to report it.
This one's a bit tricky: your string is actually being bridged to an Objective-C NSString * rather than a C char *:
(lldb) p str
(const char *) $0 = 0x3cbe9f4c5d32b745 ""
(lldb) p (id)str
(NSTaggedPointerString *) $1 = 0x3cbe9f4c5d32b745 #"Test"
(If you're wondering why it's an NSTaggedPointerString rather than just an NSString, this article is a great read -- in short, the string is short enough to be stored directly in the bytes of the pointer variable rather than in an object on the heap.
Looking at the source code for withVaList, we see that a type's va_list representation is determined by its implementation of the _cVarArgEncoding property of the CVarArg protocol. The standard library has some implementations of this protocol for some basic integer and pointer types, but there's nothing for String here. So who's converting our string to an NSString?
Searching around the Swift repo on GitHub, we find that Foundation is the culprit:
//===----------------------------------------------------------------------===//
// CVarArg for bridged types
//===----------------------------------------------------------------------===//
extension CVarArg where Self: _ObjectiveCBridgeable {
/// Default implementation for bridgeable types.
public var _cVarArgEncoding: [Int] {
let object = self._bridgeToObjectiveC()
_autorelease(object)
return _encodeBitsAsWords(object)
}
}
In plain English: any object which can be bridged to Objective-C is encoded as a vararg by converting to an Objective-C object and encoding a pointer to that object. C varargs are not type-safe, so your test_va_arg_str just assumes it's a char* and passes it to puts, which crashes.
So is this a bug? I don't think so -- I suppose this behavior is probably intentional for compatibility with functions like NSLog that are more commonly used with Objective-C objects than C ones. However, it's certainly a surprising pitfall, and it's probably one of the reasons why Swift doesn't like to let you call C variadic functions.
You'll want to work around this by manually converting your strings to C-strings. This can get a bit ugly if you have an array of strings that you want to convert without making unnecessary copies, but here's a function that should be able to do it.
extension Collection where Element == String {
/// Converts an array of strings to an array of C strings, without copying.
func withCStrings<R>(_ body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
return try withCStrings(head: [], body: body)
}
// Recursively call withCString on each of the strings.
private func withCStrings<R>(head: [UnsafePointer<CChar>],
body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
if let next = self.first {
// Get a C string, add it to the result array, and recurse on the remainder of the collection
return try next.withCString { cString in
var head = head
head.append(cString)
return try dropFirst().withCStrings(head: head, body: body)
}
} else {
// Base case: no more strings; call the body closure with the array we've built
return try body(head)
}
}
}
func withVaListOfCStrings<R>(_ args: [String], body: (CVaListPointer) -> R) -> R {
return args.withCStrings { cStrings in
withVaList(cStrings, body)
}
}
let argsStr: [String] = ["Test", "Testing", "The test"]
withVaListOfCStrings(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
// Output:
// Printing 3 strings...
// Test
// Testing
// The test

pass a swift var to a C api as void**

I have a C api that looks as follows
struct foo_private_t;
typedef foo_private_t* foo_t;
void foo_func(void**x);
Where the API is intended to be used like this
foo_t x;
void foo_func((void**) &x);
Why the API takes a void** and not a foo_t* is beyond the scope of this question. The problem is when I try to call this API from swift. First I import the C header into swift via the bridging header. Then I try to invoke foo_func with a pointer to a swift object.
var x:foo_t?
foo_func(&x)
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'
That error is expected, I need a pointer to the pointer, so I tried.
withUnsafeMutablePointer(to: x){ x_p in foo_func(x_p) }
// error is cannot convert value of type 'UnsafeMutablePointer<_>' to expected argument type 'UnsafeMutablePointer<UnsafeMutableRawPointer?>!'
This also seems reasonable as x_p is similar to &x, a single level of pointerness. The next attempt I would have expected to work.
withUnsafeMutablePointer(to: x){ x_p in foo_func(&x_p) }
// error is cannot pass immutable value of type 'UnsafeMutableRawPointer?' as inout argument
Searching around for this error reveals that if I was calling a swift function I should use the inout modifier to a parameter. But since I am calling a C api I am not sure that I can make such a modification. How can I pass a pointer that is a mutable value?
If the intention is to pass the address of x to the C function
in a way that foo_func() can assign a new value to x (which
is what the C code
foo_t x;
void foo_func((void**) &x);
does) then it would be:
var x: foo_t?
withUnsafeMutablePointer(to: &x) {
$0.withMemoryRebound(to: UnsafeMutableRawPointer?.self, capacity: 1) {
foo_func($0)
}
}
Inside withUnsafeMutablePointer(), $0 is a
UnsafeMutablePointer<foo_t?>
and this is rebound to a pointer of the expected type
UnsafeMutablePointer<UnsafeMutableRawPointer?>
I was able to get this to work.
var e = UnsafeMutableRawPointer(x)
foo_func(&e)
x is already a pointer, so it can be converted to a raw pointer. Then I need a pointer to that raw pointer, so I take the address of e. I guess I need the e variable because an implicit temporary value cannot be passed as an argument to an inout parameter. E.g.
foo_func(&UnsafeMutableRawPointer(x))
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'

Simple Pointer Operations in Swift?

Let's say I do the following in C++:
int i = 1;
int* ptr = &i;
*ptr = 2;
cout << i << '\n';
And I want to do something similar in swift. Could I do the following?
var i : Int = 1
var iptr : UnsafeMutablePointer<Int> = &i
iptr.memory = 2
print(i)
And achieve the same result?
Yes-ish.
You can't do it exactly as you've attempted in the question. It won't compile. Swift won't let you directly access the address of a value like this. At the end of the day, the reason is mostly because there's simply no good reason to do so.
We do see the & operator in Swift however.
First of all, there is the inout keyword when declaring function parameters:
func doubleIfPositive(inout value: Float) -> Bool {
if value > 0 {
value *= 2
return true
}
return false
}
And to call this method, we'd need the & operator:
let weMadeARadian = doubleIfPositive(&pi)
We can see it similarly used when we have a function which takes an argument of type UnsafeMutablePointer (and other variants of these pointer structs). In this specific case, it's primarily for interoperability with C & Objective-C, where we could declare a method as such:
bool doubleIfPositive(float * value) -> bool {
if (value > 0) {
value *= 2;
return true;
}
return false;
}
The Swift interface for that method ends up looking somethin like this:
func doubleIfPositive(value: UnsafeMutablePointer<Float>) -> Bool
And calling this method from Swift actually looks just like it did before when using the inout approach:
let weMadeARadian = doubleIfPositive(&pi)
But these are the only two uses of this & operator I can find in Swift.
With that said, we can write a function that makes use of the second form of passing an argument into a method with the & operator and returns that variable wrapped in an unsafe mutable pointer. It looks like this:
func addressOf<T>(value: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T> {
return value
}
And it behaves about as you'd expect from your original code snippet:
var i: Int = 1
var iPtr = addressOf(&i)
iPtr.memory = 2
print(i) // prints 2
As noted by Kevin in the comments, we can also directly allocate memory if we want.
var iPtr = UnsafeMutablePointer<Int>.alloc(1)
The argument 1 here is effectively the mount of space to allocate. This says we want to allocate enough memory for a single Int.
This is roughly equivalent to the following C code:
int * iPtr = malloc(1 * sizeof(int));
BUT...
If you're doing any of this for anything other than interoperability with C or Objective-C, you're most likely not Swifting correctly. So before you start running around town with pointers to value types in Swift, please, make sure it's what you absolutely need to be doing. I've been writing Swift since release, and I've never found the need for any of these shenanigans.
Like this (not the only way, but it's clear):
var i : Int = 1
withUnsafeMutablePointer(&i) {
iptr -> () in
iptr.memory = 2
}
print(i)
Not a very interesting example, but it is completely parallel to your pseudo-code, and we really did reach right into the already allocated memory and alter it, which is what you wanted to do.
This sort of thing gets a lot more interesting when what you want to do is something like cycle thru memory just as fast as doing pointer arithmetic in C.

Convert String to UnsafeMutablePointer<char_t> in Swift

I'm working with a third party c API I'm trying to call one of the functions with a simple string. Something like this:
some_c_func("aString");
I get a build error:
Type 'UnsafeMutablePointer<char_t>' does not conform to protocol 'StringLiteralConvertible'
I've seen some suggestions to use utf8 on String or similar conversions, which gets nearly there, but with the following error:
some_c_func("aString".cStringUsingEncoding(NSUTF8StringEncoding));
'UnsafePointer<Int8>' is not convertible to 'UnsafeMutablePointer<char_t>'
How can I create an UnsafeMutablePointer?
It all depends on what char_t is.
If char_t converts to Int8 then the following will work.
if let cString = str.cStringUsingEncoding(NSUTF8StringEncoding) {
some_c_func(strdup(cString))
}
This can be collapsed to
some_c_func(strdup(str.cStringUsingEncoding(NSUTF8StringEncoding)!))
WARNING! This second method will cause a crash if func cStringUsingEncoding(_:) returns nil.
Updating for Swift 3, and to fix memory leak
If the C string is only needed in a local scope, then no strdup() is needed.
guard let cString = str.cString(using: .utf8) else {
return
}
some_c_func(cString)
cString will have the same memory lifecycle as str (well similar at least).
If the C string needs to live outside the local scope, then you will need a copy. That copy will need to be freed.
guard let interimString = str.cString(using: .utf8), let cString = strdup(interimString) else {
return
}
some_c_func(cString)
//…
free(cString)
it may be simpler than that - many C APIs pass strings around as char * types, and swift treats these as unsafe.
try updating the C API (good) or hack it's header files (bad) to declare these as const char * instead.
in my experience this allows you to pass standard swift String types directly to the C API.
apparently a constant is required, in order to conform to the protocol.
I haven't tried passing strings like that, but I have a C function that I call from Swift, that takes a lot more parameters than shown here, among which is a reference to a Swift C typecast buffer to hold an error string. The compiler doesn't complain and the function call works. Hopefully this will steer you closer to the answer and you can provide an update with the final answer or someone else can.
var err = [CChar](count: 256, repeatedValue: 0)
var rv = somefunc((UnsafeMutablePointer<Int8>)(err))
if (rv < 0) {
println("Error \(err)")
return
}

Swift define double pointer for struct defined in c

I have a library which contains this function:
void create_pointer(Pointer **pointer);
It takes a pointer's pointer and allocates memory for it. in c, I can do it like this
Pointer *pointer;
create_pointer(&pointer);
then I have a pointer's instance.
But now I want to use this function in Swift. How?
I have no details about Pointer, I only know it's a struct, defined like this
typedef struct Pointer Pointer;
Let's start with a C example
typedef struct {
NSUInteger someNumber;
} SomeStruct;
void create_some_struct(SomeStruct **someStruct) {
*someStruct = malloc(sizeof(SomeStruct));
(*someStruct)->someNumber = 20;
}
In C, you would use it like this:
//pointer to our struct, initially empty
SomeStruct *s = NULL;
//calling the function
create_some_struct(&s);
In Swift:
//declaring a pointer is simple
var s: UnsafePointer<SomeStruct> = UnsafePointer<SomeStruct>.null()
//well, this seems to be almost the same thing :)
create_some_struct(&s)
println("Number: \(s.memory.someNumber)"); //prints 20
Edit:
If your pointer is an opaque type (e.g. void *), you have to use
var pointer: COpaquePointer = COpaquePointer.null()
Note that Swift is not designed to interact with C code easily. C code is mostly unsafe and Swift is designed for safety, that's why the Swift code is a bit complicated to write. Obj-C wrappers for C libraries make the task much easier.