Skip to content

Commit ba48d32

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. (cherry picked from commit 159851d)
1 parent c42ffff commit ba48d32

File tree

11 files changed

+187
-42
lines changed

11 files changed

+187
-42
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ set(WPE_PUBLIC_HEADERS
6666

6767
add_library(wpe SHARED
6868
src/input.c
69+
src/alloc.c
70+
src/input-xkb.c
6971
src/key-unicode.c
7072
src/loader.c
7173
src/pasteboard.c

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ endif
8484

8585
libwpe = library('wpe-' + api_version,
8686
'src/input.c',
87+
'src/alloc.c',
8788
'src/key-unicode.c',
8889
'src/loader.c',
8990
'src/pasteboard.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/input.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
@@ -26,10 +26,11 @@
2626

2727
#include "../include/wpe/input.h"
2828

29+
#include "alloc-private.h"
2930
#include <locale.h>
3031
#include <stdlib.h>
31-
#include <xkbcommon/xkbcommon.h>
3232
#include <xkbcommon/xkbcommon-compose.h>
33+
#include <xkbcommon/xkbcommon.h>
3334

3435
struct wpe_input_xkb_context {
3536
struct xkb_context* context;
@@ -42,7 +43,7 @@ wpe_input_xkb_context_get_default()
4243
{
4344
static struct wpe_input_xkb_context* s_xkb_context = NULL;
4445
if (!s_xkb_context) {
45-
s_xkb_context = calloc(1, sizeof(struct wpe_input_xkb_context));
46+
s_xkb_context = wpe_calloc(1, sizeof(struct wpe_input_xkb_context));
4647
s_xkb_context->context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
4748
}
4849

@@ -228,7 +229,8 @@ wpe_input_xkb_context_get_entries_for_key_code(struct wpe_input_xkb_context* xkb
228229
if (syms[sym] == key) {
229230
if (++array_size > array_allocated_size) {
230231
array_allocated_size += 4;
231-
array = (struct wpe_input_xkb_keymap_entry*)realloc(array, array_allocated_size * sizeof(struct wpe_input_xkb_keymap_entry));
232+
array =
233+
wpe_realloc(array, array_allocated_size * sizeof(struct wpe_input_xkb_keymap_entry));
232234
}
233235
struct wpe_input_xkb_keymap_entry* entry = &array[array_size - 1];
234236

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;

src/renderer-backend-egl.c

Lines changed: 12 additions & 17 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,20 +26,18 @@
2626

2727
#include "../include/wpe/renderer-backend-egl.h"
2828

29+
#include "alloc-private.h"
2930
#include "loader-private.h"
3031
#include "renderer-backend-egl-private.h"
31-
#include <stdlib.h>
3232

3333
struct wpe_renderer_backend_egl*
3434
wpe_renderer_backend_egl_create(int host_fd)
3535
{
36-
struct wpe_renderer_backend_egl* backend = calloc(1, sizeof(struct wpe_renderer_backend_egl));
37-
if (!backend)
38-
return 0;
36+
struct wpe_renderer_backend_egl* backend = wpe_calloc(1, sizeof(struct wpe_renderer_backend_egl));
3937

4038
backend->base.interface = wpe_load_object("_wpe_renderer_backend_egl_interface");
4139
if (!backend->base.interface) {
42-
free(backend);
40+
wpe_free(backend);
4341
return 0;
4442
}
4543

@@ -54,7 +52,7 @@ wpe_renderer_backend_egl_destroy(struct wpe_renderer_backend_egl* backend)
5452
backend->base.interface->destroy(backend->base.interface_data);
5553
backend->base.interface_data = 0;
5654

57-
free(backend);
55+
wpe_free(backend);
5856
}
5957

6058
EGLNativeDisplayType
@@ -74,13 +72,11 @@ wpe_renderer_backend_egl_get_platform(struct wpe_renderer_backend_egl* backend)
7472
struct wpe_renderer_backend_egl_target*
7573
wpe_renderer_backend_egl_target_create(int host_fd)
7674
{
77-
struct wpe_renderer_backend_egl_target* target = calloc(1, sizeof(struct wpe_renderer_backend_egl_target));
78-
if (!target)
79-
return 0;
75+
struct wpe_renderer_backend_egl_target* target = wpe_calloc(1, sizeof(struct wpe_renderer_backend_egl_target));
8076

8177
target->base.interface = wpe_load_object("_wpe_renderer_backend_egl_target_interface");
8278
if (!target->base.interface) {
83-
free(target);
79+
wpe_free(target);
8480
return 0;
8581
}
8682

@@ -98,7 +94,7 @@ wpe_renderer_backend_egl_target_destroy(struct wpe_renderer_backend_egl_target*
9894
target->client = 0;
9995
target->client_data = 0;
10096

101-
free(target);
97+
wpe_free(target);
10298
}
10399

104100
void
@@ -148,13 +144,12 @@ wpe_renderer_backend_egl_target_deinitialize(struct wpe_renderer_backend_egl_tar
148144
struct wpe_renderer_backend_egl_offscreen_target*
149145
wpe_renderer_backend_egl_offscreen_target_create()
150146
{
151-
struct wpe_renderer_backend_egl_offscreen_target* target = calloc(1, sizeof(struct wpe_renderer_backend_egl_offscreen_target));
152-
if (!target)
153-
return 0;
147+
struct wpe_renderer_backend_egl_offscreen_target* target =
148+
wpe_calloc(1, sizeof(struct wpe_renderer_backend_egl_offscreen_target));
154149

155150
target->base.interface = wpe_load_object("_wpe_renderer_backend_egl_offscreen_target_interface");
156151
if (!target->base.interface) {
157-
free(target);
152+
wpe_free(target);
158153
return 0;
159154
}
160155

@@ -169,7 +164,7 @@ wpe_renderer_backend_egl_offscreen_target_destroy(struct wpe_renderer_backend_eg
169164
target->base.interface->destroy(target->base.interface_data);
170165
target->base.interface_data = 0;
171166

172-
free(target);
167+
wpe_free(target);
173168
}
174169

175170
void

0 commit comments

Comments
 (0)