Skip to content

Commit 159851d

Browse files
committed
Wrap memory allocation functions to abort on failure
Be consistent in handling memory allocation failures by always aborting execution. Previously, some call sites for malloc/calloc/realloc tried to handle allocation failures, but some others did not. Given that WebKit's FastMalloc will itself abort on allocation failures, doing the same in libwpe keeps behaviour consistent. A new "alloc-private.h" header redefines the libc functions with "wpe_" prefixes, which perform checks after invoking the libc versions, and use a common wpe_alloc_fail(). The actual implementation is done through macros in order to pass along __FILE__/__LINE__ to a set of inline functions defined directly in the header, in order to help out debug failures. As a bonus, GCC's "poison" pragma (supported by Clang, too) prevents accidental usage of the libc allocation functions. As a side effect, simplify the call sites which attempted to handle failures, which now can assume that allocations never fail.
1 parent f05f59f commit 159851d

File tree

12 files changed

+191
-53
lines changed

12 files changed

+191
-53
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ set(WPE_PUBLIC_HEADERS
7777

7878
add_library(
7979
wpe
80+
src/alloc.c
8081
src/input-xkb.c
8182
src/key-unicode.c
8283
src/pasteboard.c

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ if pkg_cflags.length() > 0
8181
endif
8282

8383
libwpe = library('wpe-' + api_version,
84+
'src/alloc.c',
8485
'src/gamepad.c',
8586
'src/input-xkb.c',
8687
'src/key-unicode.c',

src/alloc-private.h

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (C) 2022 Igalia S.L.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
* 1. Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright
11+
* notice, this list of conditions and the following disclaimer in the
12+
* documentation and/or other materials provided with the distribution.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17+
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18+
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#ifndef wpe_alloc_private_h
28+
#define wpe_alloc_private_h
29+
30+
#include <stdlib.h>
31+
32+
#if defined(__has_attribute) && __has_attribute(noreturn)
33+
#define WPE_NORETURN __attribute__((noreturn))
34+
#else
35+
#define WPE_NORETURN
36+
#endif /* __has_attribute(noreturn) */
37+
38+
#if defined(__has_attribute) && __has_attribute(alloc_size)
39+
#define WPE_ALLOCSIZE(...) __attribute__((alloc_size(__VA_ARGS__)))
40+
#else
41+
#define WPE_ALLOCSIZE(...)
42+
#endif /* __has_attribute(alloc_size) */
43+
44+
#if defined(__has_attribute) && __has_attribute(malloc)
45+
#define WPE_MALLOC __attribute__((malloc))
46+
#else
47+
#define WPE_MALLOC
48+
#endif /* __has_attribute(malloc) */
49+
50+
#if defined(__has_attribute) && __has_attribute(warn_unused_result)
51+
#define WPE_USERESULT __attribute__((warn_unused_result))
52+
#else
53+
#define WPE_USERESULT
54+
#endif /* __has_attribute(warn_unused_result) */
55+
56+
#ifdef __cplusplus
57+
extern "C"
58+
#endif /* __cplusplus */
59+
WPE_NORETURN void
60+
wpe_alloc_fail(const char* file, unsigned line, size_t amount);
61+
62+
WPE_ALLOCSIZE(1, 2)
63+
WPE_MALLOC WPE_USERESULT static inline void*
64+
wpe_calloc_impl(size_t nmemb, size_t size, const char* file, unsigned line)
65+
{
66+
void* p = calloc(nmemb, size);
67+
if (p)
68+
return p;
69+
70+
wpe_alloc_fail(file, line, nmemb * size);
71+
}
72+
73+
WPE_ALLOCSIZE(2)
74+
WPE_USERESULT static inline void*
75+
wpe_realloc_impl(void* p, size_t size, const char* file, unsigned line)
76+
{
77+
if ((p = realloc(p, size)))
78+
return p;
79+
80+
wpe_alloc_fail(file, line, size);
81+
}
82+
83+
WPE_ALLOCSIZE(1)
84+
WPE_MALLOC WPE_USERESULT static inline void*
85+
wpe_malloc_impl(size_t size, const char* file, unsigned line)
86+
{
87+
void* p = malloc(size);
88+
if (p)
89+
return p;
90+
91+
wpe_alloc_fail(file, line, size);
92+
}
93+
94+
#define wpe_calloc(nmemb, size) wpe_calloc_impl((nmemb), (size), __FILE__, __LINE__)
95+
#define wpe_realloc(p, size) wpe_realloc_impl((p), (size), __FILE__, __LINE__)
96+
#define wpe_malloc(size) wpe_malloc_impl((size), __FILE__, __LINE__)
97+
#define wpe_free free
98+
99+
/* Prevent usage of unwrapped functions from this point onwards. */
100+
#pragma GCC poison malloc
101+
#pragma GCC poison realloc
102+
#pragma GCC poison calloc
103+
#pragma GCC poison free
104+
105+
#undef WPE_ALLOCSIZE
106+
#undef WPE_MALLOC
107+
#undef WPE_NORETURN
108+
#undef WPE_USERESULT
109+
110+
#endif /* wpe_alloc_private_h */

src/alloc.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (C) 2022 Igalia S.L.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
* 1. Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright
11+
* notice, this list of conditions and the following disclaimer in the
12+
* documentation and/or other materials provided with the distribution.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17+
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18+
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#include "alloc-private.h"
28+
29+
#include <stdio.h>
30+
31+
void
32+
wpe_alloc_fail(const char* file, unsigned line, size_t amount)
33+
{
34+
fprintf(stderr, "%s:%u: failed to allocate %zu bytes\n", file, line, amount);
35+
fflush(stderr);
36+
abort();
37+
}

src/gamepad.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020

2121
#include "../include/wpe/gamepad.h"
2222

23+
#include "alloc-private.h"
2324
#include <stdint.h>
24-
#include <stdlib.h>
2525

2626
struct wpe_gamepad_provider {
2727
void* backend;
@@ -44,10 +44,7 @@ wpe_gamepad_provider_create(void)
4444
if (!provider_interface)
4545
return NULL;
4646

47-
struct wpe_gamepad_provider* provider = calloc(1, sizeof(struct wpe_gamepad_provider));
48-
if (!provider)
49-
return NULL;
50-
47+
struct wpe_gamepad_provider* provider = wpe_calloc(1, sizeof(struct wpe_gamepad_provider));
5148
if (provider_interface->create)
5249
provider->backend = provider_interface->create(provider);
5350
return provider;
@@ -62,7 +59,7 @@ wpe_gamepad_provider_destroy(struct wpe_gamepad_provider* provider)
6259
if (provider_interface && provider_interface->destroy)
6360
provider_interface->destroy(provider->backend);
6461
provider->backend = NULL;
65-
free(provider);
62+
wpe_free(provider);
6663
}
6764

6865
void
@@ -119,10 +116,7 @@ wpe_gamepad_create(unsigned gamepad_id)
119116
if (!gamepad_interface)
120117
return NULL;
121118

122-
struct wpe_gamepad* gamepad = calloc(1, sizeof(struct wpe_gamepad));
123-
if (!gamepad)
124-
return NULL;
125-
119+
struct wpe_gamepad* gamepad = wpe_calloc(1, sizeof(struct wpe_gamepad));
126120
if (gamepad_interface->create)
127121
gamepad->backend = gamepad_interface->create(gamepad, gamepad_id);
128122
return gamepad;
@@ -137,7 +131,7 @@ wpe_gamepad_destroy(struct wpe_gamepad* gamepad)
137131
if (gamepad_interface && gamepad_interface->destroy)
138132
gamepad_interface->destroy(gamepad->backend);
139133
gamepad->backend = NULL;
140-
free(gamepad);
134+
wpe_free(gamepad);
141135
}
142136

143137
void

src/input-xkb.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2015, 2016 Igalia S.L.
2+
* Copyright (C) 2015, 2016, 2022 Igalia S.L.
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -29,10 +29,11 @@
2929
#include "../include/wpe/input-xkb.h"
3030
#include "../include/wpe/input.h"
3131

32+
#include "alloc-private.h"
3233
#include <locale.h>
3334
#include <stdlib.h>
34-
#include <xkbcommon/xkbcommon.h>
3535
#include <xkbcommon/xkbcommon-compose.h>
36+
#include <xkbcommon/xkbcommon.h>
3637

3738
struct wpe_input_xkb_context {
3839
struct xkb_context* context;
@@ -45,7 +46,7 @@ wpe_input_xkb_context_get_default()
4546
{
4647
static struct wpe_input_xkb_context* s_xkb_context = NULL;
4748
if (!s_xkb_context) {
48-
s_xkb_context = calloc(1, sizeof(struct wpe_input_xkb_context));
49+
s_xkb_context = wpe_calloc(1, sizeof(struct wpe_input_xkb_context));
4950
s_xkb_context->context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
5051
}
5152

@@ -231,7 +232,8 @@ wpe_input_xkb_context_get_entries_for_key_code(struct wpe_input_xkb_context* xkb
231232
if (syms[sym] == key) {
232233
if (++array_size > array_allocated_size) {
233234
array_allocated_size += 4;
234-
array = (struct wpe_input_xkb_keymap_entry*)realloc(array, array_allocated_size * sizeof(struct wpe_input_xkb_keymap_entry));
235+
array =
236+
wpe_realloc(array, array_allocated_size * sizeof(struct wpe_input_xkb_keymap_entry));
235237
}
236238
struct wpe_input_xkb_keymap_entry* entry = &array[array_size - 1];
237239

src/loader.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2015, 2016 Igalia S.L.
2+
* Copyright (C) 2015, 2016, 2022 Igalia S.L.
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,9 @@
2626

2727
#include "loader-private.h"
2828

29+
#include "alloc-private.h"
2930
#include <dlfcn.h>
3031
#include <stdio.h>
31-
#include <stdlib.h>
3232
#include <string.h>
3333

3434
static void* s_impl_library = 0;
@@ -54,7 +54,7 @@ wpe_loader_set_impl_library_name(const char* impl_library_name)
5454
return;
5555

5656
if (len > IMPL_LIBRARY_NAME_BUFFER_SIZE)
57-
s_impl_library_name = (char *)malloc(len);
57+
s_impl_library_name = wpe_malloc(len);
5858
else
5959
s_impl_library_name = s_impl_library_name_buffer;
6060
memcpy(s_impl_library_name, impl_library_name, len);

src/pasteboard-generic.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2015, 2016 Igalia S.L.
2+
* Copyright (C) 2015, 2016, 2022 Igalia S.L.
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -26,6 +26,7 @@
2626

2727
#include "pasteboard-private.h"
2828

29+
#include "alloc-private.h"
2930
#include <cstdlib>
3031
#include <cstring>
3132
#include <map>
@@ -51,7 +52,8 @@ struct wpe_pasteboard_interface generic_pasteboard_interface = {
5152
if (!length)
5253
return;
5354

54-
out_vector->strings = static_cast<struct wpe_pasteboard_string*>(calloc(length, sizeof(struct wpe_pasteboard_string)));
55+
out_vector->strings =
56+
static_cast<struct wpe_pasteboard_string*>(wpe_calloc(length, sizeof(struct wpe_pasteboard_string)));
5557
out_vector->length = length;
5658
memset(out_vector->strings, 0, sizeof(struct wpe_pasteboard_string) * length);
5759

src/pasteboard.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "pasteboard-private.h"
2828

29+
#include "alloc-private.h"
2930
#include "loader-private.h"
3031
#include <stdlib.h>
3132
#include <string.h>
@@ -36,16 +37,15 @@ wpe_pasteboard_string_initialize(struct wpe_pasteboard_string* string, const cha
3637
if (string->data)
3738
return;
3839

39-
string->data = calloc(in_length, sizeof(char));
40+
string->data = wpe_calloc(in_length, sizeof(char));
4041
string->length = in_length;
4142
memcpy(string->data, in_string, in_length);
4243
}
4344

4445
void
4546
wpe_pasteboard_string_free(struct wpe_pasteboard_string* string)
4647
{
47-
if (string->data)
48-
free((void*)string->data);
48+
wpe_free(string->data);
4949
string->data = 0;
5050
string->length = 0;
5151
}
@@ -56,7 +56,7 @@ wpe_pasteboard_string_vector_free(struct wpe_pasteboard_string_vector* vector)
5656
if (vector->strings) {
5757
for (uint64_t i = 0; i < vector->length; ++i)
5858
wpe_pasteboard_string_free(&vector->strings[i]);
59-
free(vector->strings);
59+
wpe_free(vector->strings);
6060
}
6161
vector->strings = 0;
6262
vector->length = 0;
@@ -67,7 +67,7 @@ wpe_pasteboard_get_singleton()
6767
{
6868
static struct wpe_pasteboard* s_pasteboard = 0;
6969
if (!s_pasteboard) {
70-
s_pasteboard = calloc(1, sizeof(struct wpe_pasteboard));
70+
s_pasteboard = wpe_calloc(1, sizeof(struct wpe_pasteboard));
7171
s_pasteboard->interface = wpe_load_object("_wpe_pasteboard_interface");
7272
if (!s_pasteboard->interface)
7373
s_pasteboard->interface = &noop_pasteboard_interface;

0 commit comments

Comments
 (0)