mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 16:10: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
|
# 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
|
# and internally and don't want those values leak into the public API
|
||||||
Checks: >
|
Checks: >
|
||||||
|
-clang-analyzer-unix.Malloc,
|
||||||
-clang-analyzer-optin.core.EnumCastOutOfRange
|
-clang-analyzer-optin.core.EnumCastOutOfRange
|
||||||
WarningsAsErrors: true
|
WarningsAsErrors: true
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include <libudev.h>
|
#include <libudev.h>
|
||||||
|
|
||||||
#include "libinput.h"
|
#include "libinput.h"
|
||||||
|
#include "util-mem.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle to the quirks context.
|
* Handle to the quirks context.
|
||||||
|
|
@ -179,6 +180,8 @@ quirks_init_subsystem(const char *data_path,
|
||||||
struct quirks_context *
|
struct quirks_context *
|
||||||
quirks_context_unref(struct quirks_context *ctx);
|
quirks_context_unref(struct quirks_context *ctx);
|
||||||
|
|
||||||
|
DEFINE_UNREF_CLEANUP_FUNC(quirks_context);
|
||||||
|
|
||||||
struct quirks_context *
|
struct quirks_context *
|
||||||
quirks_context_ref(struct quirks_context *ctx);
|
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
|
#endif
|
||||||
|
|
||||||
#include "util-macros.h"
|
#include "util-macros.h"
|
||||||
|
#include "util-mem.h"
|
||||||
|
|
||||||
#define yesno(b) ((b) ? "yes" : "no")
|
#define yesno(b) ((b) ? "yes" : "no")
|
||||||
#define truefalse(b) ((b) ? "true" : "false")
|
#define truefalse(b) ((b) ? "true" : "false")
|
||||||
|
|
@ -334,6 +335,13 @@ strv_free(char **strv) {
|
||||||
free (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.
|
* parse a string containing a list of doubles into a double array.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
#include "util-ratelimit.h"
|
#include "util-ratelimit.h"
|
||||||
#include "util-stringbuf.h"
|
#include "util-stringbuf.h"
|
||||||
#include "util-matrix.h"
|
#include "util-matrix.h"
|
||||||
|
#include "util-mem.h"
|
||||||
#include "util-input-event.h"
|
#include "util-input-event.h"
|
||||||
#include "util-newtype.h"
|
#include "util-newtype.h"
|
||||||
|
|
||||||
|
|
@ -2119,6 +2120,71 @@ START_TEST(newtype_test)
|
||||||
}
|
}
|
||||||
END_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)
|
int main(void)
|
||||||
{
|
{
|
||||||
struct litest_runner *runner = litest_runner_new();
|
struct litest_runner *runner = litest_runner_new();
|
||||||
|
|
@ -2189,6 +2255,7 @@ int main(void)
|
||||||
ADD_TEST(multivalue_test);
|
ADD_TEST(multivalue_test);
|
||||||
|
|
||||||
ADD_TEST(newtype_test);
|
ADD_TEST(newtype_test);
|
||||||
|
ADD_TEST(attribute_cleanup);
|
||||||
|
|
||||||
enum litest_runner_result result = litest_runner_run_tests(runner);
|
enum litest_runner_result result = litest_runner_run_tests(runner);
|
||||||
litest_runner_destroy(runner);
|
litest_runner_destroy(runner);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue