mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 04:30:06 +01:00
util: add various helper functions to use __attribute__(cleanup)
Taken from libei, with slight modifications. The general approach is: basic data types use _autofoo_ to call the maching foo function on cleanup. Struct types use _unref_, _destory_, _free_, whichever applies to that struct. Notably: attribute syntax depends on where it's declared [1] so in the following examles only a, b, and d have the autofree attribute: _autofree_ char *a, *b; char *c, _autofree *d; Simplest way to ensure it's all correct to keep the declarations one per line. [1] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1184>
This commit is contained in:
parent
436eb42044
commit
76c87d2486
5 changed files with 234 additions and 0 deletions
|
|
@ -1,5 +1,7 @@
|
|||
# optin.core.unix.Malloc: disabled so we can use __attribute__((cleanup)) without leak complaints
|
||||
# optin.core.EnumCastOutOfRange: disabled because we use a lot of "wrong" enum values for testing
|
||||
# and internally and don't want those values leak into the public API
|
||||
Checks: >
|
||||
-clang-analyzer-unix.Malloc,
|
||||
-clang-analyzer-optin.core.EnumCastOutOfRange
|
||||
WarningsAsErrors: true
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <libudev.h>
|
||||
|
||||
#include "libinput.h"
|
||||
#include "util-mem.h"
|
||||
|
||||
/**
|
||||
* Handle to the quirks context.
|
||||
|
|
@ -179,6 +180,8 @@ quirks_init_subsystem(const char *data_path,
|
|||
struct quirks_context *
|
||||
quirks_context_unref(struct quirks_context *ctx);
|
||||
|
||||
DEFINE_UNREF_CLEANUP_FUNC(quirks_context);
|
||||
|
||||
struct quirks_context *
|
||||
quirks_context_ref(struct quirks_context *ctx);
|
||||
|
||||
|
|
|
|||
154
src/util-mem.h
Normal file
154
src/util-mem.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* Use: _cleanup_(somefunction) struct foo *bar;
|
||||
*/
|
||||
#define _cleanup_(_x) __attribute__((cleanup(_x)))
|
||||
|
||||
/**
|
||||
* Use: _unref_(foo) struct foo *bar;
|
||||
*
|
||||
* This requires foo_unrefp() to be present, use DEFINE_UNREF_CLEANUP_FUNC.
|
||||
*/
|
||||
#define _unref_(_type) __attribute__((cleanup(_type##_unrefp))) struct _type
|
||||
|
||||
/**
|
||||
* Use: _destroy_(foo) struct foo *bar;
|
||||
*
|
||||
* This requires foo_destroyp() to be present, use DEFINE_UNREF_CLEANUP_FUNC.
|
||||
*/
|
||||
#define _destroy_(_type) __attribute__((cleanup(_type##_destroyp))) struct _type
|
||||
|
||||
/**
|
||||
* Use: _free_(foo) struct foo *bar;
|
||||
*
|
||||
* This requires foo_freep() to be present, use DEFINE_FREE_CLEANUP_FUNC.
|
||||
*/
|
||||
#define _free_(_type) __attribute__((cleanup(_type##_freep))) struct _type
|
||||
|
||||
static inline void _free_ptr_(void *p) { free(*(void**)p); }
|
||||
/**
|
||||
* Use: _autofree_ char *data;
|
||||
*/
|
||||
#define _autofree_ _cleanup_(_free_ptr_)
|
||||
|
||||
static inline void _close_fd_(int *fd) { if (*fd != -1) close(*fd); }
|
||||
|
||||
/**
|
||||
* Use: _autoclose_ int fd = open(...);
|
||||
*/
|
||||
#define _autoclose_ _cleanup_(_close_fd_)
|
||||
|
||||
static inline void _close_file_(FILE **fp) { if (*fp) fclose(*fp); }
|
||||
|
||||
/**
|
||||
* Use: _autofclose_ FILE *fp = fopen(...);
|
||||
*/
|
||||
#define _autofclose_ _cleanup_(_close_file_)
|
||||
|
||||
/**
|
||||
* Use:
|
||||
* DEFINE_TRIVIAL_CLEANUP_FUNC(struct foo *, foo_unref)
|
||||
* _cleanup_(foo_unrefp) struct foo *bar;
|
||||
*/
|
||||
#define DEFINE_TRIVIAL_CLEANUP_FUNC(_type, _func) \
|
||||
static inline void _func##p(_type *_p) { \
|
||||
if (*_p) \
|
||||
_func(*_p); \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
|
||||
/**
|
||||
* Define a cleanup function for the struct type foo with a matching
|
||||
* foo_unref(). Use:
|
||||
* DEFINE_UNREF_CLEANUP_FUNC(foo)
|
||||
* _unref_(foo) struct foo *bar;
|
||||
*/
|
||||
#define DEFINE_UNREF_CLEANUP_FUNC(_type) \
|
||||
static inline void _type##_unrefp(struct _type **_p) { \
|
||||
if (*_p) \
|
||||
_type##_unref(*_p); \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
|
||||
/**
|
||||
* Define a cleanup function for the struct type foo with a matching
|
||||
* foo_destroy(). Use:
|
||||
* DEFINE_DESTROY_CLEANUP_FUNC(foo)
|
||||
* _destroy_(foo) struct foo *bar;
|
||||
*/
|
||||
#define DEFINE_DESTROY_CLEANUP_FUNC(_type) \
|
||||
static inline void _type##_destroyp(struct _type **_p) {\
|
||||
if (*_p) \
|
||||
_type##_destroy(*_p); \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
|
||||
/**
|
||||
* Define a cleanup function for the struct type foo with a matching
|
||||
* foo_free(). Use:
|
||||
* DEFINE_FREE_CLEANUP_FUNC(foo)
|
||||
* _free_(foo) struct foo *bar;
|
||||
*/
|
||||
#define DEFINE_FREE_CLEANUP_FUNC(_type) \
|
||||
static inline void _type##_freep(struct _type **_p) {\
|
||||
if (*_p) \
|
||||
_type##_free(*_p); \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
|
||||
static inline void*
|
||||
_steal(void *ptr) {
|
||||
void **original = (void**)ptr;
|
||||
void *swapped = *original;
|
||||
*original = NULL;
|
||||
return swapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the pointer content and resets the data to NULL.
|
||||
* This circumvents _cleanup_ handling for that pointer.
|
||||
* Use:
|
||||
* _cleanup_free_ char *data = malloc();
|
||||
* return steal(&data);
|
||||
*
|
||||
*/
|
||||
#define steal(ptr_) \
|
||||
(typeof(*ptr_))_steal(ptr_)
|
||||
|
||||
static inline int
|
||||
steal_fd(int *fd) {
|
||||
int copy = *fd;
|
||||
*fd = -1;
|
||||
return copy;
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@
|
|||
#endif
|
||||
|
||||
#include "util-macros.h"
|
||||
#include "util-mem.h"
|
||||
|
||||
#define yesno(b) ((b) ? "yes" : "no")
|
||||
#define truefalse(b) ((b) ? "true" : "false")
|
||||
|
|
@ -334,6 +335,13 @@ strv_free(char **strv) {
|
|||
free (strv);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char **, strv_free);
|
||||
|
||||
/**
|
||||
* Use: _autostrvfree_ char **strv = ...;
|
||||
*/
|
||||
#define _autostrvfree_ _cleanup_(strv_freep)
|
||||
|
||||
/**
|
||||
* parse a string containing a list of doubles into a double array.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "util-ratelimit.h"
|
||||
#include "util-stringbuf.h"
|
||||
#include "util-matrix.h"
|
||||
#include "util-mem.h"
|
||||
#include "util-input-event.h"
|
||||
#include "util-newtype.h"
|
||||
|
||||
|
|
@ -2119,6 +2120,71 @@ START_TEST(newtype_test)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
struct sunref {};
|
||||
struct sdestroy {};
|
||||
struct sfree{};
|
||||
|
||||
static void sunref_unref(struct sunref *s) { free(s); };
|
||||
static void sdestroy_destroy(struct sdestroy *s) { free(s); };
|
||||
static void sfree_free(struct sfree *s) { free(s); };
|
||||
|
||||
DEFINE_UNREF_CLEANUP_FUNC(sunref);
|
||||
DEFINE_DESTROY_CLEANUP_FUNC(sdestroy);
|
||||
DEFINE_FREE_CLEANUP_FUNC(sfree);
|
||||
|
||||
START_TEST(attribute_cleanup)
|
||||
{
|
||||
/* These tests will likely only show up in valgrind,
|
||||
* the various asserts are just to shut up the compiler
|
||||
* about unused variables
|
||||
*/
|
||||
{
|
||||
_autofree_ char *autofree = zalloc(64);
|
||||
litest_assert(autofree);
|
||||
}
|
||||
{
|
||||
_autofree_ char *stolen = zalloc(64);
|
||||
free(steal(&stolen));
|
||||
}
|
||||
{
|
||||
_autoclose_ int fd = open("/proc/self/cmdline", O_RDONLY);
|
||||
litest_assert_int_ge(fd, 0);
|
||||
|
||||
_autoclose_ int badfd = -1;
|
||||
litest_assert_int_eq(badfd, -1);
|
||||
|
||||
_autoclose_ int stealfd = open("/proc/self/cmdline", O_RDONLY);
|
||||
steal_fd(&stealfd);
|
||||
litest_assert_int_eq(stealfd, -1);
|
||||
}
|
||||
{
|
||||
_autostrvfree_ char **strv = zalloc(3 * sizeof(*strv));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
strv[i] = strdup_printf("element %d", i);
|
||||
}
|
||||
|
||||
_autostrvfree_ char **badstrv = NULL;
|
||||
litest_assert_ptr_null(badstrv);
|
||||
}
|
||||
{
|
||||
_autofclose_ FILE *fp = fopen("/proc/self/cmdline", "r");
|
||||
litest_assert_ptr_notnull(fp);
|
||||
|
||||
_autofclose_ FILE *badfd = NULL;
|
||||
litest_assert_ptr_null(badfd);
|
||||
}
|
||||
{
|
||||
_unref_(sunref) *s = zalloc(sizeof(*s));
|
||||
}
|
||||
{
|
||||
_destroy_(sdestroy) *s = zalloc(sizeof(*s));
|
||||
}
|
||||
{
|
||||
_free_(sfree) *s = zalloc(sizeof(*s));
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct litest_runner *runner = litest_runner_new();
|
||||
|
|
@ -2189,6 +2255,7 @@ int main(void)
|
|||
ADD_TEST(multivalue_test);
|
||||
|
||||
ADD_TEST(newtype_test);
|
||||
ADD_TEST(attribute_cleanup);
|
||||
|
||||
enum litest_runner_result result = litest_runner_run_tests(runner);
|
||||
litest_runner_destroy(runner);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue