Long to CValuesRef<time_tVar>? segfaults


#1

Straightforward code does not work, and I cannot find any better API to do this, but the problem seems to be quite simple, I am sure other people tried it.

The following code gives me segmentation fault:

val metadataTime: Long = 1523720871L
val mtRef: CValuesRef<time_tVar>? = metadataTime.toCPointer<time_tVar>()
val gmtRef = gmtime(mtRef)

Nothing in StableRef seems suitable, and I do not see other way to transform a Long into CPointer.


#2

Long.toCPointer() is an unsafe cast between Long and any pointer type. If you use it on a value, that does contain the address of a valid memory location, you will create an invalid pointer. Using an invalid pointer usually leads to segmentation faults. You code is roughly equivalent to the following C code:

long metadataTime = 1523720871;
time_t* mtRef = (time_t*) metadataTime;
struct tm* gmtRef = gmtime(mtRef);

What I assume you want to do is convert your Long literal to a time_t and call gmtimeon the resulting time_t. The thing is that gmtime takes the argument by reference rather than by value. You should be able to do the following:

val gmtRef = gmtime(cValuesOf(1523720871L.convert()))

The convert call is mainly there for portability. Depending on your platform, you may not even need it.


#3

https://github.com/msink/kotlin-libui/blob/main/libui/src/nativeMain/kotlin/widgets.kt#L371

/** The current value in Unix epoch */
    var value: Long
        get() = memScoped {
            val tm = alloc<tm>()
            getValue(tm.ptr)
            mktime(tm.ptr)
        }
        set(value) = memScoped {
            val time = alloc<time_tVar>()
            time.value = value
            setValue(localtime(time.ptr)!!)
        }

#4

Thank you @Varia, that is exactly what I needed!

To make it easier for others, I’ve created a small PR to add it as a sample to kotlin-native repo: