Archivi tag: tips

Swift and pointers, news in Beta 3 and 4

In this post: https://www.lombax.it/?p=302 you have learned how to play with pointers in Swift.
Things have changed in latest betas, and more researches came in a better, shorter and more concise code. In short:

– CMutablePointer has been removed
– Code like this:

// swift side
 var opaque = COpaquePointer.null() // create a new opaque pointer pointing to null
 TestClass.writeString(&opaque)
 var string = Unmanaged.fromOpaque(opaque).takeRetainedValue()
 println(string)
 // this prints pippo pluto

has been revealed to be not safe:
There are circumstances in which Swift does not give you the original address of the variable, but instead gives you an address of a temporary variable that will be assigned back to the original once the call is over. That means you can’t count on the address of opaque being valid after the call to TestClass.writeString(&opaque). So, starting at the line ” var string = Unmanaged.fromOpaque(opaque).takeRetainedValue()”, the code can fail

Now, let’s say that we want to create a C/Objc function that takes all kind of objects and values (simply, it can receive a void** pointer), and pass a value back to Swift.
In this example we will pass in an NSString, changing its value in Objc and then reading it back in Swift. There are better methods to do this kind of things with NSString, passing a void** is used mainly to manage buffers, but in the example we’ll use an NSString for leaving things simple.

The Objc method is this

// with this objc function I completely replace the pointer
 + (void)writeString:(void **)var
 {
     NSString *oldString = CFBridgingRelease(*var); // since we are transferring opaque pointers, ARC can't help us. So, we have to release the old string before replacing it, otherwise it will leak 
     NSString *aString = [[NSString alloc] initWithFormat:@"pippo %@", @"pluto"];
     *var = (void *)CFBridgingRetain(aString); // Since aString will be released by ARC when the method ends, we need to send an additional retain. This retain is balanced by ARC on the Swift side
 }

Now, on the Swift part, the code is more simple than the previous version:

var aString : NSString = NSString(string: "test") // create the string
withUnsafePointer(&aString) { (arg: UnsafePointer) -> () in
     var aPtr = reinterpretCast(arg) as UnsafePointer<UnsafePointer<()>>
     TestMe.writeString(aPtr)
}
println(aString) // this will print "pippo pluto"

Some things to know

1) withUnsafePointer is a function that takes: an inout parameter (&parameterName) and a closure, where an arg (of type UnsafePointer) is passed in.
It can be written even in this way

withUnsafePointer(&aString, { … closure ….})

However, Swift give you a convenient way to put the closure after the parentheses. For this, look at the “Trailing Closures” chapter in the Swift Programming Language Book

2) reinterpretCast() permits to easily change the type of a pointer to another. Since Swift types are all reference types, and we want to obtain the void** pointer:
– when we pass in &aString we obtain a pointer to a Swift Reference type to an NSString, so a pointer to a pointer, and so a void**. We need only to make it “more generic”, and we to this casting to UnsafePointer<UnsafePointer<()>>
() is a TypeAlias to Void, so aPtr will be a pointer to a void pointer

Swift and mach_override, an (unsafe) alternative to objc method swizzling

UPDATE: the example code on Github (at the end of the article) has been updated for Swift 5 syntax on may 26th, 2019.
Nothing changed except the mangled names of the Swift functions, now they have a $ dollar sign in front, and when calling dlsym() you must leave out the “_” at the beginning. Look the code for further details.

Objective-c method dispatching is dynamic. This means that, when you call for example an instance method, the objc runtime “searches” the address of the underlying function (*) in a dynamical way. It uses objc_msgSend() for the message dispatching.
I don’t want to go into details here, there is a lot of documentation on the web about it.

(*) every objective c method is a plain c function that takes a _cmd (selector) as the first parameter, and self as the second parameters, then a variable list of parameters.

One advantage of the dynamic dispatching is that you can add classes, variables and methods at runtime.

This is not possible with Swift, since it is based on a vtable approach (*)
(*) This is true for plain swift classes, since classes the inherith from objective-c uses, for compatibility reasons, the dynamic dispatching and the runtime of objective c. In some cases, even the vtable is not used: the function calls are inlined

This means that there is no dynamic search of the functions/methods at runtime, their addresses are statically written at compile time inside the vtable, and it’s not possible to change them at runtime.

If you try to look at the symbols of a Swift compiled app, you will see something like this (OverrideTest is a binary name that I’m analyzing):

LombaXAir:MacOS Lombardo$ nm OverrideTest
 00000001000071e0 t _Mx_mem_size
 00000001000071c0 t _Mx_reg_size
 U _NSApplicationMain
 U _OBJC_CLASS_$_NSObject
 U _OBJC_CLASS_$_NSWindow
 0000000100010f90 S _OBJC_CLASS_$__TtC12OverrideTest11AppDelegate
 U _OBJC_METACLASS_$_NSObject
 0000000100011070 D _OBJC_METACLASS_$__TtC12OverrideTest11AppDelegate
 0000000100011010 s _OBJC_METACLASS_$___ARCLite__
 U __Block_copy
 0000000100004480 t __OSSwapInt32
 0000000100004490 t __OSSwapInt64
 0000000100001700 T __TF12OverrideTest16doSomethingSwiftFT_T_
 0000000100001aa0 T __TF12OverrideTest26doSomethingSwiftOverriddenFT_T_
 0000000100001820 T __TFC12OverrideTest11AppDelegate13aTestFunctionfS0_FT_T_
 00000001000018b0 T __TFC12OverrideTest11AppDelegate18anOverrideFunctionfS0_FT_T_
 00000001000017a0 T __TFC12OverrideTest11AppDelegate24applicationWillTerminatefS0_FGSqCSo14NSNotification_T_
 0000000100001690 T __TFC12OverrideTest11AppDelegate29applicationDidFinishLaunchingfS0_FGSqCSo14NSNotification_T_
 0000000100001a40 T __TFC12OverrideTest11AppDelegateCfMS0_FT_S0_
 0000000100001940 T __TFC12OverrideTest11AppDelegateD
 00000001000019b0 T __TFC12OverrideTest11AppDelegatecfMS0_FT_S0_
 0000000100001590 T __TFC12OverrideTest11AppDelegateg6windowXwGSQCSo8NSWindow_
 0000000100001640 T __TFC12OverrideTest11AppDelegates6windowXwGSQCSo8NSWindow_
 U __TFSS37_convertFromBuiltinUTF16StringLiteralfMSSFTBp17numberOfCodeUnitsBw_SS
... continue

Symbols like

__TFC12OverrideTest11AppDelegate13aTestFunctionfS0_FT_T_

are plain function/method names, mangled ( see Name Mangling ), that can be called by a C/ObjectiveC function without problems.
You can call them with the static address, or searching by name through dlsym (see this post: Swift Performselector alternative )

So, returning to the original topic, how to do something like method swizzling in Swift?

There is an alternative called mach_override. This is not safe and I discourage you to include it in a shipping application, however it’s possible.

mach_override “simply” add a jmp inside the assembly of the original function, making it jump to another custom function, and then jump back to the original one, if you want.

More info about mach_override Here (Github) and Here an high level explanation on how it works

After including mach_override in your project, you can override a method implementation with a c function like this:

void override()
 {
    void (*landing)(void * par);
    void (*originalFunctionAddress)(void * par);
    const void (*overrideFunctionAddress)(void * par);
   *(void **) (&originalFunctionAddress) = dlsym(RTLD_DEFAULT, "_TF15OverrideTestIOS16doSomethingSwiftFT_T_");
   *(void **) (&overrideFunctionAddress) = dlsym(RTLD_DEFAULT, "_TF15OverrideTestIOS26doSomethingSwiftOverriddenFT_T_");
   mach_override_ptr(originalFunctionAddress, overrideFunctionAddress, (void**)&landing);
}

Method names are taken with “nm” from command line, but you can try to mangle it at runtime since the mangling syntax has been reverse engineered (an example by Evan Swick Here )

the “par” parameter is because every swift instance method underlying function, takes “self” as the last parameter.

To see this code in action, download a working example (for mac) from my GitHub account

Execute after upload script on vsftpd

Premessa/Disclaimer: da un po' di tempo a questa parte sto "coltivando" una cartella chiamata "Appunti di informatica" sul mio Mac. In questa cartella raccolgo appunti sui più svariati argomenti e mini-guide per ricordarmi "come si fa" qualcosa, man mano che mi ritrovo ad affrontarle. Gli argomenti spaziano dalla gestione sistemistica in ambito Windows-Linux-OSX, allo sviluppo software su iOS e PHP, con qualche variazione sul tema. Le mini-guide saranno spesso brevi e molto pratiche, soprattutto perchè non ho molto tempo per abbellirle e renderle accattivanti per il pubblico, se vi servono dettagli non esitate a contattarmi.

First thing to do: go inside your vsftpd.conf file and enable the xfer log

xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
xferlog_std_format=NO

then, create this bash script (i’m not a bash expert so many things can be not optimized, but the important thing is that this script works 😉

#!/bin/bash
#put inside this dir the list of directories where you want to change permissions
#since vsftpd logfile doesn’t give us the full path, we have to try to apply the permissions to all directories
function changePermission {
local finalfilename=$1
chown www-data:www-data "/path/without/lasts_lash$finalfilename"
chmod 775 "/path/without/last_slash$finalfilename"
}

#tail -F on the log file,
tail -F /var/log/vsftpd.log | while read line; do
#if OK UPLOAD or OK MKDIR is found in the log line
if echo "$line" | grep -q 'OK UPLOAD:'; then
#cut the found line to find the start of the file name (-d, search for a comma delimiter, -f2 takes the second parameter delimited by the previously configured delimiter)
filename=$(echo "$line" | cut -d, -f2)
#cut the found line to remove the first space and the “
filename2=$(echo "$filename" | cut -c 3-)

#cut the found line to remove the last “
finalfilename=${filename2%?}
#executes the function
changePermission "$finalfilename"
fi
if echo "$line" | grep -q 'OK MKDIR:'; then
filename=$(echo "$line" | cut -d, -f2)
filename2=$(echo "$filename" | cut -c 3-)
finalfilename=${filename2%?}
changePermission "$finalfilename"
fi
done

This script must be executed one time (at the boot, for example).
It will monitor the ftp log, and when “OK UPLOAD:” or “OK MKDIR:” is found, applies the permission to the files.

Eseguire un resize online di /root su Linux, con LVM e Ext4

Premessa/Disclaimer: da un po' di tempo a questa parte sto "coltivando" una cartella chiamata "Appunti di informatica" sul mio Mac. In questa cartella raccolgo appunti sui più svariati argomenti e mini-guide per ricordarmi "come si fa" qualcosa, man mano che mi ritrovo ad affrontarle. Gli argomenti spaziano dalla gestione sistemistica in ambito Windows-Linux-OSX, allo sviluppo software su iOS e PHP, con qualche variazione sul tema. Le mini-guide saranno spesso brevi e molto pratiche, soprattutto perchè non ho molto tempo per abbellirle e renderle accattivanti per il pubblico, se vi servono dettagli non esitate a contattarmi.

Oggi ho scaricato un virtual appliance chiamato Turnkey Linux. Macchina virtuale già pronta per essere installata su cluster VMWare,  stack LAMP già installato e configurato.
Problema: il disco principale ha, di default, 20 gb, che per le mie necessità non sono sufficienti.
Ho deciso di espandere la partizione / (root) a 50GB.

Breve guida di come ho risolto (per la cronaca: filesystem Ext4 su LVM)

Parte fisica
/dev/sda1 <— 1gb, boot
/dev/sda2 <- 19gb, root, con LVM

Parte logica (LVM)
/dev/mapper/turnkey-boot
/dev/mapper/turnkey-root

Per farlo:

– spegnere la macchina, ingrandire il disco virtuale di quanto desiderato (esempio 50GB).
– fare fdisk /dev/sda
– eliminare la partizione sda2 RICORDANDO ESATTAMENTE IL CILINDRO DI PARTENZA (START)
– ricreare subito sda2 con lo stesso cilindro di partenza (altrimenti la macchina non partirà) ma con ultimo cilindro al max spazio disponibile
– write delle modifiche
– riavvio
– dare pvresize /dev/sda2 (questo comando estende la partizione fisica allo spazio totale disponibile)
– dare lvextend -l +100%FREE /dev/mapper/turnkey-root (questo comando estende il Logical Volume)
– dare resize2fs /dev/mapper/turnkey-root (questo comando espande il Filesystem)

Enjoy