}
// We're all out of addresses.
- exit_configuration(&cache->config_tree);
+ exit_configuration(cache->config_tree);
+ cache->config_tree = NULL;
+
return false;
}
}
if(cache->config_tree) {
- exit_configuration(&cache->config_tree);
+ exit_configuration(cache->config_tree);
+ cache->config_tree = NULL;
}
if(cache->ai) {
void close_address_cache(address_cache_t *cache) {
if(cache->config_tree) {
- exit_configuration(&cache->config_tree);
+ exit_configuration(cache->config_tree);
+ cache->config_tree = NULL;
}
if(cache->ai) {
void add_recent_address(address_cache_t *cache, const sockaddr_t *sa);
const sockaddr_t *get_recent_address(address_cache_t *cache);
-address_cache_t *open_address_cache(struct node_t *node);
-void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa);
void close_address_cache(address_cache_t *cache);
+address_cache_t *open_address_cache(node_t *node) ATTR_DEALLOCATOR(close_address_cache);
+void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa);
#endif
static size_t data_buffer_length = 0;
static uint8_t *data_buffer = NULL;
+static void tun_error(char *format, ...) ATTR_FORMAT(printf, 1, 2);
static void tun_error(char *format, ...) {
va_list vl;
va_start(vl, format);
typedef struct chacha_poly1305_ctx chacha_poly1305_ctx_t;
-extern chacha_poly1305_ctx_t *chacha_poly1305_init(void);
extern void chacha_poly1305_exit(chacha_poly1305_ctx_t *);
+extern chacha_poly1305_ctx_t *chacha_poly1305_init(void) ATTR_DEALLOCATOR(chacha_poly1305_exit);
extern bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const uint8_t *key);
extern bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
return xzalloc(sizeof(cipher_t));
}
-void cipher_free(cipher_t **cipher) {
- if(cipher && *cipher) {
- cipher_close(*cipher);
- free(*cipher);
- *cipher = NULL;
+void cipher_free(cipher_t *cipher) {
+ if(cipher) {
+ cipher_close(cipher);
+ free(cipher);
}
}
#error Incorrect cryptographic library, please reconfigure.
#endif
-extern cipher_t *cipher_alloc(void) ATTR_MALLOC;
-extern void cipher_free(cipher_t **cipher);
+extern void cipher_free(cipher_t *cipher);
+extern cipher_t *cipher_alloc(void) ATTR_MALLOC ATTR_DEALLOCATOR(cipher_free);
extern bool cipher_open_by_name(cipher_t *cipher, const char *name);
extern bool cipher_open_by_nid(cipher_t *cipher, nid_t nid);
extern void cipher_close(cipher_t *cipher);
tree->delete = (splay_action_t) free_config;
}
-void exit_configuration(splay_tree_t **config_tree) {
- splay_delete_tree(*config_tree);
- *config_tree = NULL;
+void exit_configuration(splay_tree_t *config_tree) {
+ splay_delete_tree(config_tree);
}
config_t *new_config(void) {
extern bool bypass_security;
extern list_t cmdline_conf;
-extern splay_tree_t *create_configuration(void);
+extern void exit_configuration(splay_tree_t *config_tree);
+extern splay_tree_t *create_configuration(void) ATTR_MALLOC ATTR_DEALLOCATOR(exit_configuration);
extern void init_configuration(splay_tree_t *);
-extern void exit_configuration(splay_tree_t **config_tree);
-extern config_t *new_config(void) ATTR_MALLOC;
extern void free_config(config_t *config);
+extern config_t *new_config(void) ATTR_MALLOC ATTR_DEALLOCATOR(free_config);
extern void config_add(splay_tree_t *config_tree, config_t *config);
extern config_t *lookup_config(splay_tree_t *config_tree, const char *variable);
extern config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *config);
free(c->hostname);
if(c->config_tree) {
- exit_configuration(&c->config_tree);
+ exit_configuration(c->config_tree);
+ c->config_tree = NULL;
}
free(c);
legacy_crypto_t out; /* cipher/digest we will use to send data to him */
} legacy_ctx_t;
-legacy_ctx_t *new_legacy_ctx(rsa_t *rsa) ATTR_MALLOC;
+legacy_ctx_t *new_legacy_ctx(rsa_t *rsa);
void free_legacy_ctx(legacy_ctx_t *ctx);
#endif
extern void init_connections(void);
extern void exit_connections(void);
-extern connection_t *new_connection(void) ATTR_MALLOC;
extern void free_connection(connection_t *c);
+extern connection_t *new_connection(void) ATTR_MALLOC ATTR_DEALLOCATOR(free_connection);
extern void connection_add(connection_t *c);
extern void connection_del(connection_t *c);
extern bool dump_connections(struct connection_t *c);
return xzalloc(sizeof(digest_t));
}
-void digest_free(digest_t **digest) {
- if(digest && *digest) {
- digest_close(*digest);
- free(*digest);
- *digest = NULL;
+void digest_free(digest_t *digest) {
+ if(digest) {
+ digest_close(digest);
+ free(digest);
}
}
extern bool digest_open_by_name(digest_t *digest, const char *name, size_t maclength);
extern bool digest_open_by_nid(digest_t *digest, nid_t nid, size_t maclength);
-extern digest_t *digest_alloc(void) ATTR_MALLOC;
-extern void digest_free(digest_t **digest);
+extern void digest_free(digest_t *digest);
+extern digest_t *digest_alloc(void) ATTR_MALLOC ATTR_DEALLOCATOR(digest_free);
extern void digest_close(digest_t *digest);
extern bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) ATTR_WARN_UNUSED;
extern bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *digestdata) ATTR_WARN_UNUSED;
#endif
#ifndef HAVE_ASPRINTF
-extern int asprintf(char **, const char *, ...);
-extern int vasprintf(char **, const char *, va_list ap);
+extern int asprintf(char **, const char *, ...) ATTR_FORMAT(printf, 2, 3);
+extern int vasprintf(char **, const char *, va_list ap) ATTR_FORMAT(printf, 2, 0);
#endif
#ifndef HAVE_GETTIMEOFDAY
typedef struct ecdh ecdh_t;
#endif
-extern ecdh_t *ecdh_generate_public(void *pubkey) ATTR_MALLOC;
-extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) ATTR_WARN_UNUSED;
extern void ecdh_free(ecdh_t *ecdh);
+extern ecdh_t *ecdh_generate_public(void *pubkey) ATTR_MALLOC ATTR_DEALLOCATOR(ecdh_free);
+extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) ATTR_WARN_UNUSED;
#endif
typedef struct ecdsa ecdsa_t;
#endif
-extern ecdsa_t *ecdsa_set_base64_public_key(const char *p) ATTR_MALLOC;
-extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa);
-extern ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) ATTR_MALLOC;
-extern ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) ATTR_MALLOC;
+extern void ecdsa_free(ecdsa_t *ecdsa);
+extern ecdsa_t *ecdsa_set_base64_public_key(const char *p) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
+extern ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
+extern ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
+extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) ATTR_MALLOC;
extern size_t ecdsa_size(ecdsa_t *ecdsa);
extern bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t inlen, void *out) ATTR_WARN_UNUSED;
extern bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t inlen, const void *out) ATTR_WARN_UNUSED;
extern bool ecdsa_active(ecdsa_t *ecdsa);
-extern void ecdsa_free(ecdsa_t *ecdsa);
#endif
#include "ecdsa.h"
-extern ecdsa_t *ecdsa_generate(void) ATTR_MALLOC;
+extern ecdsa_t *ecdsa_generate(void) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
extern bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) ATTR_WARN_UNUSED;
extern bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) ATTR_WARN_UNUSED;
#include "../utils.h"
#include "../xalloc.h"
+static ecdsa_t *ecdsa_new(void) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
+static ecdsa_t *ecdsa_new(void) {
+ return xzalloc(sizeof(ecdsa_t));
+}
+
// Get and set ECDSA keys
//
ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
return 0;
}
- ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
+ ecdsa_t *ecdsa = ecdsa_new();
len = b64decode_tinc(p, ecdsa->public, len);
if(len != 32) {
}
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
- ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
+ ecdsa_t *ecdsa = ecdsa_new();
if(read_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof(ecdsa->public))) {
return ecdsa;
}
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
- ecdsa_t *ecdsa = xmalloc(sizeof(*ecdsa));
+ ecdsa_t *ecdsa = ecdsa_new();
if(read_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof(*ecdsa))) {
return ecdsa;
extern splay_tree_t edge_weight_tree; /* Tree with all known edges sorted on weight */
extern void exit_edges(void);
-extern edge_t *new_edge(void) ATTR_MALLOC;
extern void free_edge(edge_t *e);
+extern edge_t *new_edge(void) ATTR_MALLOC ATTR_DEALLOCATOR(free_edge);
extern void init_edge_tree(splay_tree_t *tree);
extern void edge_add(edge_t *e);
extern void edge_del(edge_t *e);
fprintf(stderr, "WARNING: cannot read %s\n", host_file);
}
- ecdsa_t *ec_pub = NULL;
- read_ecdsa_public_key(&ec_pub, &config, name);
+ ecdsa_t *ec_pub = read_ecdsa_public_key(&config, name);
bool success = true;
#ifndef DISABLE_LEGACY
#endif
#endif
+#if defined(HAVE_ATTR_MALLOC_WITH_ARG)
+#define ATTR_DEALLOCATOR(dealloc) __attribute__((__malloc__(dealloc)))
+#else
+#define ATTR_DEALLOCATOR(dealloc)
+#endif
+
#ifdef HAVE_ATTR_MALLOC
#define ATTR_MALLOC __attribute__((__malloc__))
#else
return key;
}
-bool read_ecdsa_public_key(ecdsa_t **ecdsa, splay_tree_t **config_tree, const char *name) {
- if(ecdsa_active(*ecdsa)) {
- return true;
- }
-
+ecdsa_t *read_ecdsa_public_key(splay_tree_t **config_tree, const char *name) {
FILE *fp;
char *fname;
char *p;
*config_tree = create_configuration();
if(!read_host_config(*config_tree, name, true)) {
- return false;
+ return NULL;
}
}
/* First, check for simple Ed25519PublicKey statement */
if(get_config_string(lookup_config(*config_tree, "Ed25519PublicKey"), &p)) {
- *ecdsa = ecdsa_set_base64_public_key(p);
+ ecdsa_t *ecdsa = ecdsa_set_base64_public_key(p);
free(p);
- return *ecdsa != NULL;
+ return ecdsa;
}
/* Else, check for Ed25519PublicKeyFile statement and read it */
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 public key file `%s': %s",
fname, strerror(errno));
free(fname);
- return false;
+ return NULL;
}
- *ecdsa = ecdsa_read_pem_public_key(fp);
+ ecdsa_t *ecdsa = ecdsa_read_pem_public_key(fp);
- if(!*ecdsa && errno != ENOENT) {
+ if(!ecdsa && errno != ENOENT) {
logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname);
}
fclose(fp);
free(fname);
- return *ecdsa != NULL;
+ return ecdsa;
}
#ifndef DISABLE_LEGACY
if(!fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
free(fname);
- return false;
+ return NULL;
}
rsa_t *rsa = rsa_read_pem_public_key(fp);
extern bool disable_old_keys(const char *filename, const char *what);
-extern ecdsa_t *read_ecdsa_private_key(splay_tree_t *config_tree, char **keyfile);
-extern bool read_ecdsa_public_key(ecdsa_t **ecdsa, splay_tree_t **config_tree, const char *name);
+extern ecdsa_t *read_ecdsa_private_key(splay_tree_t *config_tree, char **keyfile) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
+extern ecdsa_t *read_ecdsa_public_key(splay_tree_t **config_tree, const char *name) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
#ifndef DISABLE_LEGACY
-extern rsa_t *read_rsa_private_key(splay_tree_t *config, char **keyfile);
-extern rsa_t *read_rsa_public_key(splay_tree_t *config_tree, const char *name);
+extern rsa_t *read_rsa_private_key(splay_tree_t *config, char **keyfile) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free);
+extern rsa_t *read_rsa_public_key(splay_tree_t *config_tree, const char *name) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free);
#endif
#endif // TINC_KEYS_H
/* (De)constructors */
-extern list_t *list_alloc(list_action_t delete) ATTR_MALLOC;
extern void list_free(list_t *list);
-extern list_node_t *list_alloc_node(void);
+extern list_t *list_alloc(list_action_t delete) ATTR_MALLOC ATTR_DEALLOCATOR(list_free);
+
extern void list_free_node(list_t *list, list_node_t *node);
+extern list_node_t *list_alloc_node(void) ATTR_MALLOC ATTR_DEALLOCATOR(list_free_node);
/* Insertion and deletion */
endif
endforeach
+if cc.compiles('''
+ #include <stdlib.h>
+ extern void *make() __attribute__((malloc(free)));
+ int main(void) { return 0; }
+''')
+ cdata.set('HAVE_ATTR_MALLOC_WITH_ARG', 1,
+ description: 'support for __attribute__((malloc(deallocator)))')
+endif
+
if cc.compiles('''
_Static_assert(1, "ok");
int main(void) { return 0; }
extern void receive_tcppacket(struct connection_t *c, const char *buffer, size_t length);
extern bool receive_tcppacket_sptps(struct connection_t *c, const char *buffer, size_t length);
extern void broadcast_packet(const struct node_t *n, vpn_packet_t *packet);
-extern char *get_name(void);
+extern char *get_name(void) ATTR_MALLOC;
extern void device_enable(void);
extern void device_disable(void);
extern bool setup_myself_reloadable(void);
if(!cipher_open_by_name(myself->incipher, cipher)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
- cipher_free(&myself->incipher);
+ cipher_free(myself->incipher);
+ myself->incipher = NULL;
free(cipher);
return false;
}
if(!digest_open_by_name(myself->indigest, digest, maclength)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!");
- digest_free(&myself->indigest);
+ digest_free(myself->indigest);
+ myself->indigest = NULL;
free(digest);
return false;
}
// Converts service name (as listed in /etc/services) to port number. Returns 0 on error.
extern uint16_t service_to_port(const char *service);
-extern struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) ATTR_MALLOC;
+extern struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) ATTR_DEALLOCATOR(freeaddrinfo);
extern sockaddr_t str2sockaddr(const char *address, const char *port);
extern void sockaddr2str(const sockaddr_t *sa, char **address, char **port);
extern char *sockaddr2hostname(const sockaddr_t *sa) ATTR_MALLOC;
sockaddrfree(&n->address);
#ifndef DISABLE_LEGACY
- cipher_free(&n->incipher);
- digest_free(&n->indigest);
- cipher_free(&n->outcipher);
- digest_free(&n->outdigest);
+ cipher_free(n->incipher);
+ digest_free(n->indigest);
+ cipher_free(n->outcipher);
+ digest_free(n->outdigest);
#endif
ecdsa_free(n->ecdsa);
extern splay_tree_t node_tree;
extern void exit_nodes(void);
-extern node_t *new_node(void) ATTR_MALLOC;
extern void free_node(node_t *n);
+extern node_t *new_node(void) ATTR_MALLOC ATTR_DEALLOCATOR(free_node);
extern void node_add(node_t *n);
extern void node_del(node_t *n);
extern node_t *lookup_node(char *name);
int minor = 0;
if(experimental) {
- if(c->outgoing && !read_ecdsa_public_key(&c->ecdsa, &c->config_tree, c->name)) {
+ if(c->outgoing && !ecdsa_active(c->ecdsa) && !(c->ecdsa = read_ecdsa_public_key(&c->config_tree, c->name))) {
minor = 1;
} else {
minor = myself->connection->protocol_minor;
return false;
}
- if(experimental) {
- read_ecdsa_public_key(&c->ecdsa, &c->config_tree, c->name);
+ if(experimental && !ecdsa_active(c->ecdsa)) {
+ c->ecdsa = read_ecdsa_public_key(&c->config_tree, c->name);
}
/* Ignore failures if no key known yet */
return false;
}
- if(ecdsa_active(c->ecdsa) || read_ecdsa_public_key(&c->ecdsa, &c->config_tree, c->name)) {
+ if(ecdsa_active(c->ecdsa) || (c->ecdsa = read_ecdsa_public_key(&c->config_tree, c->name))) {
char *knownkey = ecdsa_get_base64_public_key(c->ecdsa);
bool different = strcmp(knownkey, pubkey);
free(knownkey);
randomize(key, keylen);
- cipher_free(&to->incipher);
- digest_free(&to->indigest);
+ cipher_free(to->incipher);
+ to->incipher = NULL;
+
+ digest_free(to->indigest);
+ to->indigest = NULL;
if(myself->incipher) {
to->incipher = cipher_alloc();
#ifndef DISABLE_LEGACY
/* Don't use key material until every check has passed. */
- cipher_free(&from->outcipher);
- digest_free(&from->outdigest);
+ cipher_free(from->outcipher);
+ from->outcipher = NULL;
+
+ digest_free(from->outdigest);
+ from->outdigest = NULL;
#endif
if(!from->status.sptps) {
from->outcipher = cipher_alloc();
if(!cipher_open_by_nid(from->outcipher, cipher)) {
- cipher_free(&from->outcipher);
+ cipher_free(from->outcipher);
+ from->outcipher = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
return false;
}
from->outdigest = digest_alloc();
if(!digest_open_by_nid(from->outdigest, digest, maclength)) {
- digest_free(&from->outdigest);
+ digest_free(from->outdigest);
+ from->outdigest = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
return false;
}
#endif
extern void rsa_free(rsa_t *rsa);
-extern rsa_t *rsa_set_hex_public_key(const char *n, const char *e) ATTR_MALLOC;
-extern rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) ATTR_MALLOC;
-extern rsa_t *rsa_read_pem_public_key(FILE *fp) ATTR_MALLOC;
-extern rsa_t *rsa_read_pem_private_key(FILE *fp) ATTR_MALLOC;
+extern rsa_t *rsa_set_hex_public_key(const char *n, const char *e) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free);
+extern rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free);
+extern rsa_t *rsa_read_pem_public_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free);
+extern rsa_t *rsa_read_pem_private_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free);
extern size_t rsa_size(const rsa_t *rsa);
extern bool rsa_public_encrypt(rsa_t *rsa, const void *in, size_t len, void *out) ATTR_WARN_UNUSED;
extern bool rsa_private_decrypt(rsa_t *rsa, const void *in, size_t len, void *out) ATTR_WARN_UNUSED;
#include "rsa.h"
-extern rsa_t *rsa_generate(size_t bits, unsigned long exponent) ATTR_MALLOC;
+extern rsa_t *rsa_generate(size_t bits, unsigned long exponent) ATTR_DEALLOCATOR(rsa_free);
extern bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) ATTR_WARN_UNUSED;
extern bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) ATTR_WARN_UNUSED;
/* (De)constructors */
-extern splay_tree_t *splay_alloc_tree(splay_compare_t compare, splay_action_t delete) ATTR_MALLOC;
extern void splay_free_tree(splay_tree_t *tree);
+extern splay_tree_t *splay_alloc_tree(splay_compare_t compare, splay_action_t delete) ATTR_MALLOC ATTR_DEALLOCATOR(splay_free_tree);
-extern splay_node_t *splay_alloc_node(void) ATTR_MALLOC;
extern void splay_free_node(splay_tree_t *tree, splay_node_t *node);
+extern splay_node_t *splay_alloc_node(void) ATTR_MALLOC ATTR_DEALLOCATOR(splay_free_node);
/* Insertion and deletion */
extern splay_tree_t subnet_tree;
extern int subnet_compare(const struct subnet_t *a, const struct subnet_t *b);
-extern subnet_t *new_subnet(void) ATTR_MALLOC;
extern void free_subnet(subnet_t *subnet);
+extern subnet_t *new_subnet(void) ATTR_MALLOC ATTR_DEALLOCATOR(free_subnet);
extern void init_subnets(void);
extern void exit_subnets(void);
extern void init_subnet_tree(splay_tree_t *tree);
return NULL;
}
-ecdsa_t *get_pubkey(FILE *f) {
+static ecdsa_t *get_pubkey(FILE *f) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
+static ecdsa_t *get_pubkey(FILE *f) {
char buf[4096];
char *value;
extern const var_t variables[];
extern size_t rstrip(char *value);
-extern char *get_my_name(bool verbose);
+extern char *get_my_name(bool verbose) ATTR_MALLOC;
extern bool connect_tincd(bool verbose);
extern bool sendline(int fd, const char *format, ...);
extern bool recvline(int fd, char *line, size_t len);
extern int check_port(const char *name);
-extern ecdsa_t *get_pubkey(FILE *f);
#endif
extern bool check_id(const char *id);
extern bool check_netname(const char *netname, bool strict);
-char *replace_name(const char *name);
+char *replace_name(const char *name) ATTR_MALLOC;
char *absolute_path(const char *path) ATTR_MALLOC;
-extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms);
+extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms) ATTR_DEALLOCATOR(fclose);
#endif