This evening I needed to call mkdtemp(3) in a Vala project I am working on. Unfortunately its bizarre interface (it munges the string argument you pass it, and returns the same string on success or NULL on failure) makes it tricky to call correctly from Vala.
The obvious thing to do, and the first thing I tried, was:
var temp_dir = DirUtils.mkdtemp("thingXXXXXX");
Unfortunately this will result in a segmentation fault, since Vala passes the string constant straight through to mkdtemp(3) (which then tries to modify a read-only segment).
Next I tried copying the string:
var temp_dir = DirUtils.mkdtemp("thingXXXXXX".dup());
At first glance, this appeared to work (no more segfault!) but on a hunch I inspected the generated C and saw this nastiness:
temp_dir = (_tmp1_ = g_strdup (mkdtemp (_tmp0_ = g_strdup ("thingXXXXXX"))),
_g_free0 (_tmp0_), _tmp1_);
Once you get past the confusing syntax, you will notice that the string is being freed before the outer g_strdup call. So this code will probably work, most of the time, but is liable to explode at any time since it’s wrong.
If however you hold a reference to the template string around the mkdtemp(3) call, things work out properly:
{
var template = "thingXXXXXX".dup();
temp_dir = DirUtils.mkdtemp(template);
}
In this case Vala emits the following C. Although the string is copied once more than is necessary, at least the code will work correctly:
{
char* template;
char* _tmp0_;
template = g_strdup ("thingXXXXXX");
temp_dir = (_tmp0_ = g_strdup (mkdtemp (template)),
_g_free0 (temp_dir), _tmp0_);
_g_free0 (template);
}
It’s tempting to blame Vala here for not generating correct code in the first place, but I think that reference ownership semantics in the current version of Vala just aren’t rich enough to handle the very unusual interface of mkdtemp(3). So hopefully this entry will help someone else who needs to call mkdtemp(3) correctly from Vala.