Skip to content

Commit

Permalink
Wrap memory allocation functions to abort on failure
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aperezdc committed Jul 19, 2022
1 parent f05f59f commit 159851d
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 53 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ set(WPE_PUBLIC_HEADERS

add_library(
wpe
src/alloc.c
src/input-xkb.c
src/key-unicode.c
src/pasteboard.c
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ if pkg_cflags.length() > 0
endif

libwpe = library('wpe-' + api_version,
'src/alloc.c',
'src/gamepad.c',
'src/input-xkb.c',
'src/key-unicode.c',
Expand Down
110 changes: 110 additions & 0 deletions src/alloc-private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright (C) 2022 Igalia S.L.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef wpe_alloc_private_h
#define wpe_alloc_private_h

#include <stdlib.h>

#if defined(__has_attribute) && __has_attribute(noreturn)
#define WPE_NORETURN __attribute__((noreturn))
#else
#define WPE_NORETURN
#endif /* __has_attribute(noreturn) */

#if defined(__has_attribute) && __has_attribute(alloc_size)
#define WPE_ALLOCSIZE(...) __attribute__((alloc_size(__VA_ARGS__)))
#else
#define WPE_ALLOCSIZE(...)
#endif /* __has_attribute(alloc_size) */

#if defined(__has_attribute) && __has_attribute(malloc)
#define WPE_MALLOC __attribute__((malloc))
#else
#define WPE_MALLOC
#endif /* __has_attribute(malloc) */

#if defined(__has_attribute) && __has_attribute(warn_unused_result)
#define WPE_USERESULT __attribute__((warn_unused_result))
#else
#define WPE_USERESULT
#endif /* __has_attribute(warn_unused_result) */

#ifdef __cplusplus
extern "C"
#endif /* __cplusplus */
WPE_NORETURN void
wpe_alloc_fail(const char* file, unsigned line, size_t amount);

WPE_ALLOCSIZE(1, 2)
WPE_MALLOC WPE_USERESULT static inline void*
wpe_calloc_impl(size_t nmemb, size_t size, const char* file, unsigned line)
{
void* p = calloc(nmemb, size);
if (p)
return p;

wpe_alloc_fail(file, line, nmemb * size);
}

WPE_ALLOCSIZE(2)
WPE_USERESULT static inline void*
wpe_realloc_impl(void* p, size_t size, const char* file, unsigned line)
{
if ((p = realloc(p, size)))
return p;

wpe_alloc_fail(file, line, size);
}

WPE_ALLOCSIZE(1)
WPE_MALLOC WPE_USERESULT static inline void*
wpe_malloc_impl(size_t size, const char* file, unsigned line)
{
void* p = malloc(size);
if (p)
return p;

wpe_alloc_fail(file, line, size);
}

#define wpe_calloc(nmemb, size) wpe_calloc_impl((nmemb), (size), __FILE__, __LINE__)
#define wpe_realloc(p, size) wpe_realloc_impl((p), (size), __FILE__, __LINE__)
#define wpe_malloc(size) wpe_malloc_impl((size), __FILE__, __LINE__)
#define wpe_free free

/* Prevent usage of unwrapped functions from this point onwards. */
#pragma GCC poison malloc
#pragma GCC poison realloc
#pragma GCC poison calloc
#pragma GCC poison free

#undef WPE_ALLOCSIZE
#undef WPE_MALLOC
#undef WPE_NORETURN
#undef WPE_USERESULT

#endif /* wpe_alloc_private_h */
37 changes: 37 additions & 0 deletions src/alloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2022 Igalia S.L.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "alloc-private.h"

#include <stdio.h>

void
wpe_alloc_fail(const char* file, unsigned line, size_t amount)
{
fprintf(stderr, "%s:%u: failed to allocate %zu bytes\n", file, line, amount);
fflush(stderr);
abort();
}
16 changes: 5 additions & 11 deletions src/gamepad.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

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

#include "alloc-private.h"
#include <stdint.h>
#include <stdlib.h>

struct wpe_gamepad_provider {
void* backend;
Expand All @@ -44,10 +44,7 @@ wpe_gamepad_provider_create(void)
if (!provider_interface)
return NULL;

struct wpe_gamepad_provider* provider = calloc(1, sizeof(struct wpe_gamepad_provider));
if (!provider)
return NULL;

struct wpe_gamepad_provider* provider = wpe_calloc(1, sizeof(struct wpe_gamepad_provider));
if (provider_interface->create)
provider->backend = provider_interface->create(provider);
return provider;
Expand All @@ -62,7 +59,7 @@ wpe_gamepad_provider_destroy(struct wpe_gamepad_provider* provider)
if (provider_interface && provider_interface->destroy)
provider_interface->destroy(provider->backend);
provider->backend = NULL;
free(provider);
wpe_free(provider);
}

void
Expand Down Expand Up @@ -119,10 +116,7 @@ wpe_gamepad_create(unsigned gamepad_id)
if (!gamepad_interface)
return NULL;

struct wpe_gamepad* gamepad = calloc(1, sizeof(struct wpe_gamepad));
if (!gamepad)
return NULL;

struct wpe_gamepad* gamepad = wpe_calloc(1, sizeof(struct wpe_gamepad));
if (gamepad_interface->create)
gamepad->backend = gamepad_interface->create(gamepad, gamepad_id);
return gamepad;
Expand All @@ -137,7 +131,7 @@ wpe_gamepad_destroy(struct wpe_gamepad* gamepad)
if (gamepad_interface && gamepad_interface->destroy)
gamepad_interface->destroy(gamepad->backend);
gamepad->backend = NULL;
free(gamepad);
wpe_free(gamepad);
}

void
Expand Down
10 changes: 6 additions & 4 deletions src/input-xkb.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015, 2016 Igalia S.L.
* Copyright (C) 2015, 2016, 2022 Igalia S.L.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -29,10 +29,11 @@
#include "../include/wpe/input-xkb.h"
#include "../include/wpe/input.h"

#include "alloc-private.h"
#include <locale.h>
#include <stdlib.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include <xkbcommon/xkbcommon.h>

struct wpe_input_xkb_context {
struct xkb_context* context;
Expand All @@ -45,7 +46,7 @@ wpe_input_xkb_context_get_default()
{
static struct wpe_input_xkb_context* s_xkb_context = NULL;
if (!s_xkb_context) {
s_xkb_context = calloc(1, sizeof(struct wpe_input_xkb_context));
s_xkb_context = wpe_calloc(1, sizeof(struct wpe_input_xkb_context));
s_xkb_context->context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
}

Expand Down Expand Up @@ -231,7 +232,8 @@ wpe_input_xkb_context_get_entries_for_key_code(struct wpe_input_xkb_context* xkb
if (syms[sym] == key) {
if (++array_size > array_allocated_size) {
array_allocated_size += 4;
array = (struct wpe_input_xkb_keymap_entry*)realloc(array, array_allocated_size * sizeof(struct wpe_input_xkb_keymap_entry));
array =
wpe_realloc(array, array_allocated_size * sizeof(struct wpe_input_xkb_keymap_entry));
}
struct wpe_input_xkb_keymap_entry* entry = &array[array_size - 1];

Expand Down
6 changes: 3 additions & 3 deletions src/loader.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015, 2016 Igalia S.L.
* Copyright (C) 2015, 2016, 2022 Igalia S.L.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -26,9 +26,9 @@

#include "loader-private.h"

#include "alloc-private.h"
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

if (len > IMPL_LIBRARY_NAME_BUFFER_SIZE)
s_impl_library_name = (char *)malloc(len);
s_impl_library_name = wpe_malloc(len);
else
s_impl_library_name = s_impl_library_name_buffer;
memcpy(s_impl_library_name, impl_library_name, len);
Expand Down
6 changes: 4 additions & 2 deletions src/pasteboard-generic.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015, 2016 Igalia S.L.
* Copyright (C) 2015, 2016, 2022 Igalia S.L.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -26,6 +26,7 @@

#include "pasteboard-private.h"

#include "alloc-private.h"
#include <cstdlib>
#include <cstring>
#include <map>
Expand All @@ -51,7 +52,8 @@ struct wpe_pasteboard_interface generic_pasteboard_interface = {
if (!length)
return;

out_vector->strings = static_cast<struct wpe_pasteboard_string*>(calloc(length, sizeof(struct wpe_pasteboard_string)));
out_vector->strings =
static_cast<struct wpe_pasteboard_string*>(wpe_calloc(length, sizeof(struct wpe_pasteboard_string)));
out_vector->length = length;
memset(out_vector->strings, 0, sizeof(struct wpe_pasteboard_string) * length);

Expand Down
10 changes: 5 additions & 5 deletions src/pasteboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include "pasteboard-private.h"

#include "alloc-private.h"
#include "loader-private.h"
#include <stdlib.h>
#include <string.h>
Expand All @@ -36,16 +37,15 @@ wpe_pasteboard_string_initialize(struct wpe_pasteboard_string* string, const cha
if (string->data)
return;

string->data = calloc(in_length, sizeof(char));
string->data = wpe_calloc(in_length, sizeof(char));
string->length = in_length;
memcpy(string->data, in_string, in_length);
}

void
wpe_pasteboard_string_free(struct wpe_pasteboard_string* string)
{
if (string->data)
free((void*)string->data);
wpe_free(string->data);
string->data = 0;
string->length = 0;
}
Expand All @@ -56,7 +56,7 @@ wpe_pasteboard_string_vector_free(struct wpe_pasteboard_string_vector* vector)
if (vector->strings) {
for (uint64_t i = 0; i < vector->length; ++i)
wpe_pasteboard_string_free(&vector->strings[i]);
free(vector->strings);
wpe_free(vector->strings);
}
vector->strings = 0;
vector->length = 0;
Expand All @@ -67,7 +67,7 @@ wpe_pasteboard_get_singleton()
{
static struct wpe_pasteboard* s_pasteboard = 0;
if (!s_pasteboard) {
s_pasteboard = calloc(1, sizeof(struct wpe_pasteboard));
s_pasteboard = wpe_calloc(1, sizeof(struct wpe_pasteboard));
s_pasteboard->interface = wpe_load_object("_wpe_pasteboard_interface");
if (!s_pasteboard->interface)
s_pasteboard->interface = &noop_pasteboard_interface;
Expand Down
Loading

0 comments on commit 159851d

Please sign in to comment.