Consider:
#include "share/atspre_staload.hats"
%{^
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
%}
typedef statbuf = $extype "struct stat"
extern fun cstat: (string, &statbuf? >> statbuf) -> int = "mac#stat"
extern fun S_ISDIR: int -> bool = "mac#"
extern fun stat_mode: statbuf -> int = "mac#stat_mode"
%{
#define stat_mode(x) x.st_mode
%}
datavtype statbuf_vt = STAT of statbuf
fun stat(path: string): Option_vt(statbuf_vt) =
let
val buf = STAT(_)
val STAT(hole) = buf
val res = cstat(path, hole)
prval _ = fold@(buf)
in
if res = 0 then Some_vt(buf)
else
let
val ~STAT(_) = buf
in
None_vt()
end
end
implement main0() =
let
val path = "/etc/passwd"
val- ~Some_vt(~STAT(buf)) = stat(path)
in
println!(~S_ISDIR(stat_mode(buf)))
end
What is the lifetime of buf
at the end? It doesn't seem like it needs to be freed--valgrind sees 3 allocs and 3 frees, and no problems. But isn't buf
part of the memory managed by that STAT
linear object?
Note 'buf' is a flat struct. Any value that matches the pattern ~STAT(buf) is freed; before it is freed, some content in the value is copied into 'buf', which is located on the stack. The life time of 'buf' ends when the frame for calling 'main0' unwinds. There are no leaks in the presented code.