From a01b7d3ecc28e3dbfbc43008ae114ec595436653 Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Fri, 13 Oct 2023 14:26:15 -0700 Subject: [PATCH 01/15] GUACAMOLE-1867: Add convenience functions and macros for memory management. --- src/libguac/Makefile.am | 19 ++ src/libguac/guacamole/mem.h | 375 +++++++++++++++++++++++++ src/libguac/guacamole/private/mem.h | 280 ++++++++++++++++++ src/libguac/mem.c | 236 ++++++++++++++++ src/libguac/tests/Makefile.am | 13 + src/libguac/tests/alloc/alloc.c | 73 +++++ src/libguac/tests/alloc/free.c | 63 +++++ src/libguac/tests/alloc/size.c | 68 +++++ src/libguac/tests/alloc/zalloc.c | 102 +++++++ src/libguac/tests/assert-signal.h | 67 +++++ src/libguac/tests/mem/alloc.c | 73 +++++ src/libguac/tests/mem/ckd_add.c | 103 +++++++ src/libguac/tests/mem/ckd_add_or_die.c | 72 +++++ src/libguac/tests/mem/ckd_mul.c | 99 +++++++ src/libguac/tests/mem/ckd_mul_or_die.c | 68 +++++ src/libguac/tests/mem/ckd_sub.c | 105 +++++++ src/libguac/tests/mem/ckd_sub_or_die.c | 74 +++++ src/libguac/tests/mem/free.c | 63 +++++ src/libguac/tests/mem/realloc.c | 118 ++++++++ src/libguac/tests/mem/zalloc.c | 102 +++++++ 20 files changed, 2173 insertions(+) create mode 100644 src/libguac/guacamole/mem.h create mode 100644 src/libguac/guacamole/private/mem.h create mode 100644 src/libguac/mem.c create mode 100644 src/libguac/tests/alloc/alloc.c create mode 100644 src/libguac/tests/alloc/free.c create mode 100644 src/libguac/tests/alloc/size.c create mode 100644 src/libguac/tests/alloc/zalloc.c create mode 100644 src/libguac/tests/assert-signal.h create mode 100644 src/libguac/tests/mem/alloc.c create mode 100644 src/libguac/tests/mem/ckd_add.c create mode 100644 src/libguac/tests/mem/ckd_add_or_die.c create mode 100644 src/libguac/tests/mem/ckd_mul.c create mode 100644 src/libguac/tests/mem/ckd_mul_or_die.c create mode 100644 src/libguac/tests/mem/ckd_sub.c create mode 100644 src/libguac/tests/mem/ckd_sub_or_die.c create mode 100644 src/libguac/tests/mem/free.c create mode 100644 src/libguac/tests/mem/realloc.c create mode 100644 src/libguac/tests/mem/zalloc.c diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am index 963644ed..8d973877 100644 --- a/src/libguac/Makefile.am +++ b/src/libguac/Makefile.am @@ -29,6 +29,10 @@ ACLOCAL_AMFLAGS = -I m4 lib_LTLIBRARIES = libguac.la SUBDIRS = . tests +# +# Public headers +# + libguacincdir = $(includedir)/guacamole libguacinc_HEADERS = \ @@ -48,6 +52,7 @@ libguacinc_HEADERS = \ guacamole/hash.h \ guacamole/layer.h \ guacamole/layer-types.h \ + guacamole/mem.h \ guacamole/object.h \ guacamole/object-types.h \ guacamole/parser-constants.h \ @@ -79,6 +84,19 @@ libguacinc_HEADERS = \ guacamole/wol.h \ guacamole/wol-constants.h +# +# Private, installed headers +# + +libguacprivincdir = $(includedir)/guacamole/private + +libguacprivinc_HEADERS = \ + guacamole/private/mem.h + +# +# Private, non-installed headers +# + noinst_HEADERS = \ id.h \ encode-jpeg.h \ @@ -98,6 +116,7 @@ libguac_la_SOURCES = \ fips.c \ hash.c \ id.c \ + mem.c \ rwlock.c \ palette.c \ parser.c \ diff --git a/src/libguac/guacamole/mem.h b/src/libguac/guacamole/mem.h new file mode 100644 index 00000000..9a78db97 --- /dev/null +++ b/src/libguac/guacamole/mem.h @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef GUAC_MEM_H +#define GUAC_MEM_H + +/** + * Provides convenience macros/functions for performing arithmetic on size_t + * values and for allocating memory, particularly memory related to images, + * audio, etc. where there are multiple factors affecting the final size. + * + * @file mem.h + */ + +#include "private/mem.h" + +#include + +/** + * Allocates a contiguous block of memory with the specified size, returning a + * pointer to the first byte of that block of memory. If multiple sizes are + * provided, these sizes are multiplied together to produce the final size of + * the new block. If memory of the specified size cannot be allocated, or if + * multiplying the sizes would result in integer overflow, guac_error is set + * appropriately and NULL is returned. + * + * This macro is analogous to the standard malloc(), but accepts a list of size + * factors instead of a single integer size. + * + * The pointer returned by guac_mem_alloc() SHOULD be freed with a subsequent call + * to guac_mem_free(), but MAY instead be freed with a subsequent call to free(). + * + * @param ... + * A series of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the allocated block of memory, or NULL if + * such a block could not be allocated. If a block of memory could not be + * allocated, guac_error is set appropriately. + */ +#define guac_mem_alloc(...) \ + PRIV_guac_mem_alloc( \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Allocates a contiguous block of memory with the specified size and with all + * bytes initialized to zero, returning a pointer to the first byte of that + * block of memory. If multiple sizes are provided, these sizes are multiplied + * together to produce the final size of the new block. If memory of the + * specified size cannot be allocated, or if multiplying the sizes would result + * in integer overflow, guac_error is set appropriately and NULL is returned. + * + * This macro is analogous to the standard calloc(), but accepts a list of size + * factors instead of a requiring exactly two integer sizes. + * + * The pointer returned by guac_mem_zalloc() SHOULD be freed with a subsequent call + * to guac_mem_free(), but MAY instead be freed with a subsequent call to free(). + * + * @param ... + * A series of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the allocated block of memory, or NULL if + * such a block could not be allocated. If a block of memory could not be + * allocated, guac_error is set appropriately. + */ +#define guac_mem_zalloc(...) \ + PRIV_guac_mem_zalloc( \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Multiplies together each of the given values, storing the result in a size_t + * variable via the provided pointer. If the result of the multiplication + * overflows the limits of a size_t, non-zero is returned to signal failure. + * + * If the multiplication operation fails, the nature of any result stored in + * the provided pointer is undefined, as is whether a result is stored at all. + * + * For example, the following: + * @code + * size_t some_result; + * int failed = guac_mem_ckd_mul(&some_result, a, b, c); + * @endcode + * + * is equivalent in principle to: + * @code + * size_t some_result = a * b * c; + * @endcode + * + * except that it is possible for interested callers to handle overflow. + * + * @param result + * A pointer to the size_t variable that should receive the result of + * multiplying the given values. + * + * @param ... + * The size_t values that should be multiplied together. + * + * @returns + * Zero if the multiplication was successful and did not overflow the + * limits of a size_t, non-zero otherwise. + */ +#define guac_mem_ckd_mul(result, ...) \ + PRIV_guac_mem_ckd_mul( \ + result, \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Adds together each of the given values, storing the result in a size_t + * variable via the provided pointer. If the result of the addition overflows + * the limits of a size_t, non-zero is returned to signal failure. + * + * If the addition operation fails, the nature of any result stored in the + * provided pointer is undefined, as is whether a result is stored at all. + * + * For example, the following: + * @code + * size_t some_result; + * int failed = guac_mem_ckd_add(&some_result, a, b, c); + * @endcode + * + * is equivalent in principle to: + * @code + * size_t some_result = a + b + c; + * @endcode + * + * except that it is possible for interested callers to handle overflow. + * + * @param result + * A pointer to the size_t variable that should receive the result of + * adding the given values. + * + * @param ... + * The size_t values that should be added together. + * + * @returns + * Zero if the addition was successful and did not overflow the limits of a + * size_t, non-zero otherwise. + */ +#define guac_mem_ckd_add(result, ...) \ + PRIV_guac_mem_ckd_add( \ + result, \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Subtracts each of the given values from each other, storing the result in a + * size_t variable via the provided pointer. If the result of the subtraction + * overflows the limits of a size_t (goes below zero), non-zero is returned to + * signal failure. + * + * If the subtraction operation fails, the nature of any result stored in the + * provided pointer is undefined, as is whether a result is stored at all. + * + * For example, the following: + * @code + * size_t some_result; + * int failed = guac_mem_ckd_sub(&some_result, a, b, c); + * @endcode + * + * is equivalent in principle to: + * @code + * size_t some_result = a - b - c; + * @endcode + * + * except that it is possible for interested callers to handle overflow. + * + * @param result + * A pointer to the size_t variable that should receive the result of + * subtracting the given values from each other. + * + * @param ... + * The size_t values that should be subtracted from each other. + * + * @returns + * Zero if the subtraction was successful and did not overflow the limits + * of a size_t (did not go below zero), non-zero otherwise. + */ +#define guac_mem_ckd_sub(result, ...) \ + PRIV_guac_mem_ckd_sub( \ + result, \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Multiplies together each of the given values, returning the result directly. + * If the result of the multiplication overflows the limits of a size_t, + * execution of the current process is aborted entirely, and this function does + * not return. + * + * For example, the following: + * @code + * size_t some_result = guac_mem_ckd_mul_or_die(a, b, c); + * @endcode + * + * is equivalent in principle to: + * @code + * size_t some_result = a * b * c; + * @endcode + * + * except that an overflow condition will result in the process immediately + * terminating. + * + * @param ... + * The size_t values that should be multiplied together. + * + * @returns + * The result of the multiplication. If the multiplication operation would + * overflow the limits of a size_t, execution of the current process is + * aborted, and this function does not return. + */ +#define guac_mem_ckd_mul_or_die(...) \ + PRIV_guac_mem_ckd_mul_or_die( \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Adds together each of the given values, returning the result directly. If + * the result of the addition overflows the limits of a size_t, execution of + * the current process is aborted entirely, and this function does not return. + * + * For example, the following: + * @code + * size_t some_result = guac_mem_ckd_add_or_die(a, b, c); + * @endcode + * + * is equivalent in principle to: + * @code + * size_t some_result = a + b + c; + * @endcode + * + * except that an overflow condition will result in the process immediately + * terminating. + * + * @param ... + * The size_t values that should be added together. + * + * @returns + * The result of the addition. If the addition operation would overflow the + * limits of a size_t, execution of the current process is aborted, and + * this function does not return. + */ +#define guac_mem_ckd_add_or_die(...) \ + PRIV_guac_mem_ckd_add_or_die( \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Subtracts each of the given values from each other, returning the result + * directly. If the result of the subtraction overflows the limits of a size_t + * (goes below zero), execution of the current process is aborted entirely, and + * this function does not return. + * + * For example, the following: + * @code + * size_t some_result = guac_mem_ckd_sub_or_die(a, b, c); + * @endcode + * + * is equivalent in principle to: + * @code + * size_t some_result = a - b - c; + * @endcode + * + * except that an overflow condition will result in the process immediately + * terminating. + * + * @param ... + * The size_t values that should be subtracted from each other. + * + * @returns + * The result of the subtraction. If the subtraction operation would + * overflow the limits of a size_t (go below zero), execution of the + * current process is aborted, and this function does not return. + */ +#define guac_mem_ckd_sub_or_die(...) \ + PRIV_guac_mem_ckd_sub_or_die( \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Reallocates a contiguous block of memory that was previously allocated with + * guac_mem_alloc(), guac_mem_zalloc(), or guac_mem_realloc(), returning a + * pointer to the first byte of that reallocated block of memory. If multiple + * sizes are provided, these sizes are multiplied together to produce the final + * size of the new block. If memory of the specified size cannot be allocated, + * or if multiplying the sizes would result in integer overflow, guac_error is + * set appropriately, the original block of memory is left untouched, and NULL + * is returned. + * + * This macro is analogous to the standard realloc(), but accepts a list of + * size factors instead of a requiring exactly one integer size. + * + * The returned pointer may be the same as the original pointer, but this is + * not guaranteed. If the returned pointer is different, the original pointer + * is automatically freed. + * + * The pointer returned by guac_mem_realloc() SHOULD be freed with a subsequent + * call to guac_mem_free(), but MAY instead be freed with a subsequent call to + * free(). + * + * @param ... + * A series of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the reallocated block of memory, or NULL + * if such a block could not be allocated. If a block of memory could not + * be allocated, guac_error is set appropriately and the original block of + * memory is left untouched. + */ +#define guac_mem_realloc(mem, ...) \ + PRIV_guac_mem_realloc( \ + mem, \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + +/** + * Frees the memory block at the given pointer, which MUST have been allocated + * with guac_mem_alloc(), guac_mem_zalloc(), or guac_mem_realloc(). The pointer + * is automatically assigned a value of NULL after memory is freed. If the + * provided pointer is already NULL, this macro has no effect. + * + * @param mem + * A pointer to the memory to be freed. + */ +#define guac_mem_free(mem) (PRIV_guac_mem_free(mem), (mem) = NULL, (void) 0) + +/** + * Frees the memory block at the given const pointer, which MUST have been + * allocated with guac_mem_alloc(), guac_mem_zalloc(), or guac_mem_realloc(). + * As the pointer is presumed constant, it is not automatically assigned a + * value of NULL after memory is freed. If the provided pointer is NULL, this + * macro has no effect. + * + * The guac_mem_free() macro should be used in favor of this macro. This macro + * should only be used in cases where a constant pointer is absolutely + * necessary. + * + * @param mem + * A pointer to the memory to be freed. + */ +#define guac_mem_free_const(mem) PRIV_guac_mem_free((void*) (mem)) + +#endif + diff --git a/src/libguac/guacamole/private/mem.h b/src/libguac/guacamole/private/mem.h new file mode 100644 index 00000000..98668e72 --- /dev/null +++ b/src/libguac/guacamole/private/mem.h @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef GUAC_PRIVATE_MEM_H +#define GUAC_PRIVATE_MEM_H + +/** + * Provides functions used internally for allocating memory. + * + * WARNING: SYMBOLS DEFINED HERE ARE NOT INTENDED TO BE USED DIRECTLY BY + * ANYTHING OUTSIDE LIBGUAC! This header is used internally to define private + * symbols that are only intended for indirect public use through some other, + * non-private mechanism, such as a macro defined in the public API. + * + * @file mem.h + */ + +#include + +/** + * Allocates a contiguous block of memory with the specified size, returning a + * pointer to the first byte of that block of memory. If multiple sizes are + * provided, these sizes are multiplied together to produce the final size of + * the new block. If memory of the specified size cannot be allocated, or if + * multiplying the sizes would result in integer overflow, guac_error is set + * appropriately and NULL is returned. + * + * This function is analogous to the standard malloc(), but accepts a list of + * size factors instead of a single integer size. + * + * The pointer returned by PRIV_guac_mem_alloc() SHOULD be freed with a + * subsequent call to guac_mem_free() or PRIV_guac_mem_free(), but MAY instead + * be freed with a subsequent call to free(). + * + * @param factor_count + * The number of factors to multiply together to produce the desired block + * size. + * + * @param factors + * An array of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the allocated block of memory, or NULL if + * such a block could not be allocated. If a block of memory could not be + * allocated, guac_error is set appropriately. + */ +void* PRIV_guac_mem_alloc(size_t factor_count, const size_t* factors); + +/** + * Allocates a contiguous block of memory with the specified size and with all + * bytes initialized to zero, returning a pointer to the first byte of that + * block of memory. If multiple sizes are provided, these sizes are multiplied + * together to produce the final size of the new block. If memory of the + * specified size cannot be allocated, or if multiplying the sizes would result + * in integer overflow, guac_error is set appropriately and NULL is returned. + * + * This function is analogous to the standard calloc(), but accepts a list of + * size factors instead of a requiring exactly two integer sizes. + * + * The pointer returned by PRIV_guac_mem_zalloc() SHOULD be freed with a + * subsequent call to guac_mem_free() or PRIV_guac_mem_free(), but MAY instead + * be freed with a subsequent call to free(). + * + * @param factor_count + * The number of factors to multiply together to produce the desired block + * size. + * + * @param factors + * An array of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the allocated block of memory, or NULL if + * such a block could not be allocated. If a block of memory could not be + * allocated, guac_error is set appropriately. + */ +void* PRIV_guac_mem_zalloc(size_t factor_count, const size_t* factors); + +/** + * Multiplies together each of the given values, storing the result in a size_t + * variable via the provided pointer. If the result of the multiplication + * overflows the limits of a size_t, non-zero is returned to signal failure. + * + * If the multiplication operation fails, the nature of any result stored in + * the provided pointer is undefined, as is whether a result is stored at all. + * + * @param result + * A pointer to the size_t variable that should receive the result of + * multiplying the given values. + * + * @param factor_count + * The number of factors to multiply together. + * + * @param factors + * An array of one or more size_t values that should be multiplied + * together. At least one value MUST be provided. + * + * @returns + * Zero if the multiplication was successful and did not overflow the + * limits of a size_t, non-zero otherwise. + */ +int PRIV_guac_mem_ckd_mul(size_t* result, size_t factor_count, const size_t* factors); + +/** + * Adds together each of the given values, storing the result in a size_t + * variable via the provided pointer. If the result of the addition overflows + * the limits of a size_t, non-zero is returned to signal failure. + * + * If the addition operation fails, the nature of any result stored in the + * provided pointer is undefined, as is whether a result is stored at all. + * + * @param result + * A pointer to the size_t variable that should receive the result of + * adding the given values. + * + * @param term_count + * The number of terms to be added together. + * + * @param terms + * An array of one or more size_t values that should be added together. At + * least one value MUST be provided. + * + * @returns + * Zero if the addition was successful and did not overflow the limits of a + * size_t, non-zero otherwise. + */ +int PRIV_guac_mem_ckd_add(size_t* result, size_t term_count, const size_t* terms); + +/** + * Subtracts each of the given values from each other, storing the result in a + * size_t variable via the provided pointer. If the result of the subtraction + * overflows the limits of a size_t (goes below zero), non-zero is returned to + * signal failure. + * + * If the subtraction operation fails, the nature of any result stored in the + * provided pointer is undefined, as is whether a result is stored at all. + * + * @param result + * A pointer to the size_t variable that should receive the result of + * subtracting the given values from each other. + * + * @param term_count + * The number of terms to be subtracted from each other. + * + * @param terms + * An array of one or more size_t values that should be subtracted from + * each other. At least one value MUST be provided. + * + * @returns + * Zero if the subtraction was successful and did not overflow the limits + * of a size_t (did not go below zero), non-zero otherwise. + */ +int PRIV_guac_mem_ckd_sub(size_t* result, size_t term_count, const size_t* terms); + +/** + * Multiplies together each of the given values, returning the result directly. + * If the result of the multiplication overflows the limits of a size_t, + * execution of the current process is aborted entirely, and this function does + * not return. + * + * @param factor_count + * The number of factors to multiply together. + * + * @param factors + * An array of one or more size_t values that should be multiplied + * together. At least one value MUST be provided. + * + * @returns + * The result of the multiplication. If the multiplication operation would + * overflow the limits of a size_t, execution of the current process is + * aborted, and this function does not return. + */ +size_t PRIV_guac_mem_ckd_mul_or_die(size_t factor_count, const size_t* factors); + +/** + * Adds together each of the given values, returning the result directly. If + * the result of the addition overflows the limits of a size_t, execution of + * the current process is aborted entirely, and this function does not return. + * + * @param term_count + * The number of terms to be added together. + * + * @param terms + * An array of one or more size_t values that should be added together. At + * least one value MUST be provided. + * + * @returns + * The result of the addition. If the addition operation would overflow the + * limits of a size_t, execution of the current process is aborted, and + * this function does not return. + */ +size_t PRIV_guac_mem_ckd_add_or_die(size_t term_count, const size_t* terms); + +/** + * Subtracts each of the given values from each other, returning the result + * directly. If the result of the subtraction overflows the limits of a size_t + * (goes below zero), execution of the current process is aborted entirely, and + * this function does not return. + * + * @param term_count + * The number of terms to be subtracted from each other. + * + * @param terms + * An array of one or more size_t values that should be subtracted from + * each other. At least one value MUST be provided. + * + * @returns + * The result of the subtraction. If the subtraction operation would + * overflow the limits of a size_t (go below zero), execution of the + * current process is aborted, and this function does not return. + */ +size_t PRIV_guac_mem_ckd_sub_or_die(size_t term_count, const size_t* terms); + +/** + * Reallocates a contiguous block of memory that was previously allocated with + * guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of their + * PRIV_guac_*() variants, returning a pointer to the first byte of that + * reallocated block of memory. If multiple sizes are provided, these sizes are + * multiplied together to produce the final size of the new block. If memory of + * the specified size cannot be allocated, or if multiplying the sizes would + * result in integer overflow, guac_error is set appropriately, the original + * block of memory is left untouched, and NULL is returned. + * + * This function is analogous to the standard realloc(), but accepts a list of + * size factors instead of a requiring exactly one integer size. + * + * The returned pointer may be the same as the original pointer, but this is + * not guaranteed. If the returned pointer is different, the original pointer + * is automatically freed. + * + * The pointer returned by guac_mem_realloc() SHOULD be freed with a subsequent + * call to guac_mem_free() or PRIV_guac_mem_free(), but MAY instead be freed + * with a subsequent call to free(). + * + * @param factor_count + * The number of factors to multiply together to produce the desired block + * size. + * + * @param factors + * An array of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the reallocated block of memory, or NULL + * if such a block could not be allocated. If a block of memory could not + * be allocated, guac_error is set appropriately and the original block of + * memory is left untouched. + */ +void* PRIV_guac_mem_realloc(void* mem, size_t factor_count, const size_t* factors); + +/** + * Frees the memory block at the given pointer, which MUST have been allocated + * with guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of + * their PRIV_guac_*() variants. If the provided pointer is NULL, this function + * has no effect. + * + * @param mem + * A pointer to the memory to be freed. + */ +void PRIV_guac_mem_free(void* mem); + +#endif + diff --git a/src/libguac/mem.c b/src/libguac/mem.c new file mode 100644 index 00000000..c06c0ff2 --- /dev/null +++ b/src/libguac/mem.c @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "guacamole/error.h" +#include "guacamole/mem.h" +#include "guacamole/private/mem.h" + +#include +#include +#include + +/* + * ============================================================================ + * + * IMPORTANT: For compatibility with past usages of libguac, all allocation + * functions implemented here need to remain compatible with the standard + * free() function, as there are past usages of libguac functions that expect + * allocated memory to have been allocated with malloc() or similar. Some good + * examples of this would be guac_strdup() or guac_user_parse_args_string(). + * + * It is OK if these allocation functions add new functionality beyond what + * malloc() provides, but care must be taken to ensure free() can still be used + * safely and without leaks, even if guac_mem_free() will always be preferred. + * + * It is further OK for guac_mem_free() to be incompatible with free() and only + * usable on memory blocks allocated through guac_mem_alloc() and similar. + * + * ============================================================================ + */ + +int PRIV_guac_mem_ckd_mul(size_t* result, size_t factor_count, const size_t* factors) { + + /* Consider calculation invalid if no factors are provided at all */ + if (factor_count == 0) + return 1; + + /* Multiply all provided factors together */ + ssize_t size = *(factors++); + while (--factor_count && size) { + + size_t factor = *(factors++); + + /* Fail if including this additional factor would exceed SIZE_MAX */ + size_t max_factor = SIZE_MAX / size; + if (factor > max_factor) + return 1; + + size *= factor; + + } + + *result = size; + return 0; + +} + +int PRIV_guac_mem_ckd_add(size_t* result, size_t term_count, const size_t* terms) { + + /* Consider calculation invalid if no terms are provided at all */ + if (term_count == 0) + return 1; + + /* Multiply all provided terms together */ + ssize_t size = *(terms++); + while (--term_count) { + + size_t term = *(terms++); + + /* Fail if including this additional term would exceed SIZE_MAX */ + size_t max_term = SIZE_MAX - size; + if (term > max_term) + return 1; + + size += term; + + } + + *result = size; + return 0; + +} + +int PRIV_guac_mem_ckd_sub(size_t* result, size_t term_count, const size_t* terms) { + + /* Consider calculation invalid if no terms are provided at all */ + if (term_count == 0) + return 1; + + /* Multiply all provided terms together */ + ssize_t size = *(terms++); + while (--term_count) { + + size_t term = *(terms++); + + /* Fail if including this additional term would wrap past zero */ + if (term > size) + return 1; + + size -= term; + + } + + *result = size; + return 0; + +} + +size_t PRIV_guac_mem_ckd_mul_or_die(size_t factor_count, const size_t* factors) { + + /* Perform request multiplication, aborting the entire process if the + * calculation overflows */ + size_t result = 0; + if (PRIV_guac_mem_ckd_mul(&result, factor_count, factors)) + abort(); + + return result; + +} + +size_t PRIV_guac_mem_ckd_add_or_die(size_t term_count, const size_t* terms) { + + /* Perform request addition, aborting the entire process if the calculation + * overflows */ + size_t result = 0; + if (PRIV_guac_mem_ckd_add(&result, term_count, terms)) + abort(); + + return result; + +} + +size_t PRIV_guac_mem_ckd_sub_or_die(size_t term_count, const size_t* terms) { + + /* Perform request subtraction, aborting the entire process if the + * calculation overflows */ + size_t result = 0; + if (PRIV_guac_mem_ckd_sub(&result, term_count, terms)) + abort(); + + return result; + +} + +void* PRIV_guac_mem_alloc(size_t factor_count, const size_t* factors) { + + size_t size = 0; + + if (PRIV_guac_mem_ckd_mul(&size, factor_count, factors)) { + guac_error = GUAC_STATUS_NO_MEMORY; + return NULL; + } + else if (size == 0) + return NULL; + + void* mem = malloc(size); + if (mem == NULL) { + /* C does not require that malloc() set errno (though POSIX does). For + * portability, we set guac_error here regardless of the underlying + * behavior of malloc(). */ + guac_error = GUAC_STATUS_NO_MEMORY; + } + + return mem; + +} + +void* PRIV_guac_mem_zalloc(size_t factor_count, const size_t* factors) { + + size_t size = 0; + + if (PRIV_guac_mem_ckd_mul(&size, factor_count, factors)) { + guac_error = GUAC_STATUS_NO_MEMORY; + return NULL; + } + else if (size == 0) + return NULL; + + void* mem = calloc(1, size); + if (mem == NULL) { + /* C does not require that calloc() set errno (though POSIX does). For + * portability, we set guac_error here regardless of the underlying + * behavior of calloc(). */ + guac_error = GUAC_STATUS_NO_MEMORY; + } + + return mem; + +} + +void* PRIV_guac_mem_realloc(void* mem, size_t factor_count, const size_t* factors) { + + size_t size = 0; + + if (PRIV_guac_mem_ckd_mul(&size, factor_count, factors)) { + guac_error = GUAC_STATUS_NO_MEMORY; + return NULL; + } + + /* Resize to 0 is equivalent to free() */ + if (size == 0) { + guac_mem_free(mem); + return NULL; + } + + void* resized_mem = realloc(mem, size); + if (resized_mem == NULL) { + /* C does not require that realloc() set errno (though POSIX does). For + * portability, we set guac_error here regardless of the underlying + * behavior of realloc(). */ + guac_error = GUAC_STATUS_NO_MEMORY; + } + + return resized_mem; + +} + +void PRIV_guac_mem_free(void* mem) { + free(mem); +} + diff --git a/src/libguac/tests/Makefile.am b/src/libguac/tests/Makefile.am index b7452cf0..4f2f429a 100644 --- a/src/libguac/tests/Makefile.am +++ b/src/libguac/tests/Makefile.am @@ -33,10 +33,23 @@ ACLOCAL_AMFLAGS = -I m4 check_PROGRAMS = test_libguac TESTS = $(check_PROGRAMS) +noinst_HEADERS = \ + assert-signal.h + test_libguac_SOURCES = \ client/buffer_pool.c \ client/layer_pool.c \ id/generate.c \ + mem/alloc.c \ + mem/ckd_add.c \ + mem/ckd_add_or_die.c \ + mem/ckd_mul.c \ + mem/ckd_mul_or_die.c \ + mem/ckd_sub.c \ + mem/ckd_sub_or_die.c \ + mem/free.c \ + mem/realloc.c \ + mem/zalloc.c \ parser/append.c \ parser/read.c \ pool/next_free.c \ diff --git a/src/libguac/tests/alloc/alloc.c b/src/libguac/tests/alloc/alloc.c new file mode 100644 index 00000000..edb1f000 --- /dev/null +++ b/src/libguac/tests/alloc/alloc.c @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_alloc() returns NULL for all inputs involving + * at least one zero value. + */ +void test_alloc__alloc_fail_zero() { + + CU_ASSERT_PTR_NULL(guac_alloc(0)); + CU_ASSERT_PTR_NULL(guac_alloc(0, 0)); + CU_ASSERT_PTR_NULL(guac_alloc(0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_alloc(0, 0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_alloc(0, 0, 0, 0, 0)); + + CU_ASSERT_PTR_NULL(guac_alloc(1, 0)); + CU_ASSERT_PTR_NULL(guac_alloc(3, 2, 0)); + CU_ASSERT_PTR_NULL(guac_alloc(5, 0, 8, 9)); + CU_ASSERT_PTR_NULL(guac_alloc(99, 99, 99, 0, 99)); + +} + +/** + * Test which verifies that guac_alloc() successfully allocates blocks of + * memory for inputs that can reasonably be expected to succeed. + */ +void test_alloc__alloc_success() { + + void* ptr; + + ptr = guac_alloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_free(ptr); + + ptr = guac_alloc(123, 456); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_free(ptr); + + ptr = guac_alloc(123, 456, 789); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_free(ptr); + +} + +/** + * Test which verifies that guac_alloc() fails to allocate blocks of memory + * that exceed the capacity of a size_t. + */ +void test_alloc__alloc_fail_large() { + CU_ASSERT_PTR_NULL(guac_alloc(123, 456, SIZE_MAX)); + CU_ASSERT_PTR_NULL(guac_alloc(SIZE_MAX / 2, SIZE_MAX / 2)); +} + diff --git a/src/libguac/tests/alloc/free.c b/src/libguac/tests/alloc/free.c new file mode 100644 index 00000000..3a055d3d --- /dev/null +++ b/src/libguac/tests/alloc/free.c @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_free() sets the provided pointer to NULL after + * freeing. + */ +void test_alloc__free_assigns_null() { + void* ptr = guac_alloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_free(ptr); + CU_ASSERT_PTR_NULL(ptr); +} + +/** + * Test which verifies that guac_free_const() can be used to free constant + * pointers, but that those pointers are not set to NULL after freeing. + */ +void test_alloc__free_const() { + const void* ptr = guac_alloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_free_const(ptr); + CU_ASSERT_PTR_NOT_NULL(ptr); +} + +/** + * Test which verifies that guac_free() does nothing if provided a NULL + * pointer. + */ +void test_alloc__free_null() { + void* ptr = NULL; + guac_free(ptr); +} + +/** + * Test which verifies that guac_free_const() does nothing if provided a NULL + * pointer. + */ +void test_alloc__free_null_const() { + const void* ptr = NULL; + guac_free_const(ptr); +} + diff --git a/src/libguac/tests/alloc/size.c b/src/libguac/tests/alloc/size.c new file mode 100644 index 00000000..d2be0a2e --- /dev/null +++ b/src/libguac/tests/alloc/size.c @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_alloc_size() returns zero for all inputs + * involving at least one zero value. + */ +void test_alloc__size_zero() { + + CU_ASSERT_EQUAL(guac_alloc_size(0), 0); + CU_ASSERT_EQUAL(guac_alloc_size(0, 0), 0); + CU_ASSERT_EQUAL(guac_alloc_size(0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_alloc_size(0, 0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_alloc_size(0, 0, 0, 0, 0), 0); + + CU_ASSERT_EQUAL(guac_alloc_size(1, 0), 0); + CU_ASSERT_EQUAL(guac_alloc_size(3, 2, 0), 0); + CU_ASSERT_EQUAL(guac_alloc_size(5, 0, 8, 9), 0); + CU_ASSERT_EQUAL(guac_alloc_size(99, 99, 99, 0, 99), 0); + +} + +/** + * Test which verifies that guac_alloc_size() returns expected values for + * relatively small integer inputs. + */ +void test_alloc__size_small() { + + CU_ASSERT_EQUAL(guac_alloc_size(123), 123); + CU_ASSERT_EQUAL(guac_alloc_size(123, 456), 123 * 456); + CU_ASSERT_EQUAL(guac_alloc_size(123, 456, 789), 123 * 456 * 789); + +} + +/** + * Test which verifies that guac_alloc_size() returns expected values for + * relatively large integer inputs, including inputs that cause overflow + * beyond the capacity of a size_t. + */ +void test_alloc__size_large() { + + CU_ASSERT_EQUAL(guac_alloc_size(SIZE_MAX), SIZE_MAX); + + CU_ASSERT_EQUAL(guac_alloc_size(123, 456, SIZE_MAX), 0); + CU_ASSERT_EQUAL(guac_alloc_size(SIZE_MAX / 2, SIZE_MAX / 2), 0); + +} + diff --git a/src/libguac/tests/alloc/zalloc.c b/src/libguac/tests/alloc/zalloc.c new file mode 100644 index 00000000..5209921d --- /dev/null +++ b/src/libguac/tests/alloc/zalloc.c @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_zalloc() returns NULL for all inputs involving + * at least one zero value. + */ +void test_alloc__zalloc_fail_zero() { + + CU_ASSERT_PTR_NULL(guac_zalloc(0)); + CU_ASSERT_PTR_NULL(guac_zalloc(0, 0)); + CU_ASSERT_PTR_NULL(guac_zalloc(0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_zalloc(0, 0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_zalloc(0, 0, 0, 0, 0)); + + CU_ASSERT_PTR_NULL(guac_zalloc(1, 0)); + CU_ASSERT_PTR_NULL(guac_zalloc(3, 2, 0)); + CU_ASSERT_PTR_NULL(guac_zalloc(5, 0, 8, 9)); + CU_ASSERT_PTR_NULL(guac_zalloc(99, 99, 99, 0, 99)); + +} + +/** + * Returns whether all bytes within the given memory region are zero. + * + * @param ptr + * The first byte of the memory region to test. + * + * @param length + * The number of bytes within the memory region. + * + * @returns + * Non-zero if all bytes within the memory region have the value of zero, + * zero otherwise. + */ +static int is_all_zeroes(void* ptr, size_t length) { + + int result = 0; + + unsigned char* current = (unsigned char*) ptr; + for (size_t i = 0; i < length; i++) + result |= *(current++); + + return !result; + +} + +/** + * Test which verifies that guac_zalloc() successfully allocates blocks of + * memory for inputs that can reasonably be expected to succeed, and that each + * block is zeroed out. + */ +void test_alloc__zalloc_success() { + + void* ptr; + + ptr = guac_zalloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + CU_ASSERT(is_all_zeroes(ptr, 123)); + guac_free(ptr); + + ptr = guac_zalloc(123, 456); + CU_ASSERT_PTR_NOT_NULL(ptr); + CU_ASSERT(is_all_zeroes(ptr, 123 * 456)); + guac_free(ptr); + + ptr = guac_zalloc(123, 456, 789); + CU_ASSERT_PTR_NOT_NULL(ptr); + CU_ASSERT(is_all_zeroes(ptr, 123 * 456 * 789)); + guac_free(ptr); + +} + +/** + * Test which verifies that guac_zalloc() fails to allocate blocks of memory + * that exceed the capacity of a size_t. + */ +void test_alloc__zalloc_fail_large() { + CU_ASSERT_PTR_NULL(guac_zalloc(123, 456, SIZE_MAX)); + CU_ASSERT_PTR_NULL(guac_zalloc(SIZE_MAX / 2, SIZE_MAX / 2)); +} + diff --git a/src/libguac/tests/assert-signal.h b/src/libguac/tests/assert-signal.h new file mode 100644 index 00000000..76b52c2a --- /dev/null +++ b/src/libguac/tests/assert-signal.h @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef GUAC_LIBGUAC_TESTS_ASSERT_SIGNAL_H +#define GUAC_LIBGUAC_TESTS_ASSERT_SIGNAL_H + +#include +#include +#include +#include +#include + +/** + * Verifies that the given test terminates the calling process with the given + * signal. + * + * @param sig + * The signal that is expected to terminate the calling process. + * + * @param test + * The test that is expected to terminate the calling process with the + * given signal. + */ +#define ASSERT_SIGNALLED(sig, test) \ + do { \ + \ + /* Fork to ensure test can safely terminate */ \ + pid_t _child = fork(); \ + CU_ASSERT_NOT_EQUAL_FATAL(_child, -1); \ + \ + /* Run test strictly within child process */ \ + if (_child == 0) { \ + do { test; } while (0); \ + exit(0); \ + } \ + \ + /* Wait for child process to terminate */ \ + int _status = 0; \ + CU_ASSERT_EQUAL_FATAL(waitpid(_child, &_status, 0), _child); \ + \ + /* Verify process terminated with expected signal */ \ + if (WIFSIGNALED(_status)) { \ + CU_ASSERT_EQUAL(WTERMSIG(_status), (sig)); \ + } \ + else \ + CU_FAIL("Process did not terminate due to a signal"); \ + \ + } while (0) + +#endif + diff --git a/src/libguac/tests/mem/alloc.c b/src/libguac/tests/mem/alloc.c new file mode 100644 index 00000000..bec3145b --- /dev/null +++ b/src/libguac/tests/mem/alloc.c @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_mem_alloc() returns NULL for all inputs involving + * at least one zero value. + */ +void test_mem__alloc_fail_zero() { + + CU_ASSERT_PTR_NULL(guac_mem_alloc(0)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(0, 0)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(0, 0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(0, 0, 0, 0, 0)); + + CU_ASSERT_PTR_NULL(guac_mem_alloc(1, 0)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(3, 2, 0)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(5, 0, 8, 9)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(99, 99, 99, 0, 99)); + +} + +/** + * Test which verifies that guac_mem_alloc() successfully allocates blocks of + * memory for inputs that can reasonably be expected to succeed. + */ +void test_mem__alloc_success() { + + void* ptr; + + ptr = guac_mem_alloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(123, 456); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(123, 456, 789); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + +} + +/** + * Test which verifies that guac_mem_alloc() fails to allocate blocks of memory + * that exceed the capacity of a size_t. + */ +void test_mem__alloc_fail_large() { + CU_ASSERT_PTR_NULL(guac_mem_alloc(123, 456, SIZE_MAX)); + CU_ASSERT_PTR_NULL(guac_mem_alloc(SIZE_MAX / 2, SIZE_MAX / 2)); +} + diff --git a/src/libguac/tests/mem/ckd_add.c b/src/libguac/tests/mem/ckd_add.c new file mode 100644 index 00000000..f24e6247 --- /dev/null +++ b/src/libguac/tests/mem/ckd_add.c @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_mem_ckd_add() calculates results correctly for + * all inputs involving at least one zero value. + */ +void test_mem__ckd_add_zero() { + + size_t result = SIZE_MAX; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 0, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 0, 0, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 0, 1)); + CU_ASSERT_EQUAL(result, 1); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 1, 0)); + CU_ASSERT_EQUAL(result, 1); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 3, 2, 0)); + CU_ASSERT_EQUAL(result, 3 + 2); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 5, 0, 8, 9)); + CU_ASSERT_EQUAL(result, 5 + 8 + 9); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 99, 99, 99, 0, 99)); + CU_ASSERT_EQUAL(result, 99 + 99 + 99 + 99); + +} + +/** + * Test which verifies that guac_mem_ckd_add() successfully calculates expected + * values for relatively small integer inputs. + */ +void test_mem__ckd_add_small() { + + size_t result = SIZE_MAX; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 123)); + CU_ASSERT_EQUAL(result, 123); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 123, 456)); + CU_ASSERT_EQUAL(result, 123 + 456); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, 123, 456, 789)); + CU_ASSERT_EQUAL(result, 123 + 456 + 789); + +} + +/** + * Test which verifies that guac_mem_ckd_add() behaves as expected for + * relatively large integer inputs, including inputs that cause overflow beyond + * the capacity of a size_t. + */ +void test_mem__ckd_add_large() { + + size_t result = 0; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, SIZE_MAX)); + CU_ASSERT_EQUAL(result, SIZE_MAX); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_add(&result, SIZE_MAX / 2, SIZE_MAX / 2)); + CU_ASSERT_EQUAL(result, (SIZE_MAX / 2) * 2); + + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_add(&result, SIZE_MAX, 1)); + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_add(&result, 123, 456, SIZE_MAX)); + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_add(&result, SIZE_MAX / 2, SIZE_MAX / 2, 2)); + +} + diff --git a/src/libguac/tests/mem/ckd_add_or_die.c b/src/libguac/tests/mem/ckd_add_or_die.c new file mode 100644 index 00000000..497bfe3d --- /dev/null +++ b/src/libguac/tests/mem/ckd_add_or_die.c @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "assert-signal.h" + +#include +#include +#include + +/** + * Test which verifies that guac_mem_ckd_add_or_die() calculates results + * correctly for all inputs involving at least one zero value. + */ +void test_mem__ckd_add_or_die_zero() { + + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(0, 0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(0, 0, 0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(0, 1), 1); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(1, 0), 1); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(3, 2, 0), 3 + 2); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(5, 0, 8, 9), 5 + 8 + 9); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(99, 99, 99, 0, 99), 99 + 99 + 99 + 99); + +} + +/** + * Test which verifies that guac_mem_ckd_add_or_die() successfully calculates + * expected values for relatively small integer inputs. + */ +void test_mem__ckd_add_or_die_small() { + + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(123), 123); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(123, 456), 123 + 456); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(123, 456, 789), 123 + 456 + 789); + +} + +/** + * Test which verifies that guac_mem_ckd_add_or_die() behaves as expected for + * relatively large integer inputs, including inputs that cause overflow beyond + * the capacity of a size_t. + */ +void test_mem__ckd_add_or_die_large() { + + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(SIZE_MAX), SIZE_MAX); + CU_ASSERT_EQUAL(guac_mem_ckd_add_or_die(SIZE_MAX / 2, SIZE_MAX / 2), (SIZE_MAX / 2) * 2); + + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_add_or_die(SIZE_MAX, 1)); + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_add_or_die(123, 456, SIZE_MAX)); + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_add_or_die(SIZE_MAX / 2, SIZE_MAX / 2, 2)); + +} + diff --git a/src/libguac/tests/mem/ckd_mul.c b/src/libguac/tests/mem/ckd_mul.c new file mode 100644 index 00000000..847c6f19 --- /dev/null +++ b/src/libguac/tests/mem/ckd_mul.c @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_mem_ckd_mul() calculates zero values for all + * inputs involving at least one zero value. + */ +void test_mem__ckd_mul_zero() { + + size_t result = SIZE_MAX; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 0, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 0, 0, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 0, 1)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 1, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 3, 2, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 5, 0, 8, 9)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 99, 99, 99, 0, 99)); + CU_ASSERT_EQUAL(result, 0); + +} + +/** + * Test which verifies that guac_mem_ckd_mul() successfully calculates expected + * values for relatively small integer inputs. + */ +void test_mem__ckd_mul_small() { + + size_t result = SIZE_MAX; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 123)); + CU_ASSERT_EQUAL(result, 123); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 123, 456)); + CU_ASSERT_EQUAL(result, 123 * 456); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, 123, 456, 789)); + CU_ASSERT_EQUAL(result, 123 * 456 * 789); + +} + +/** + * Test which verifies that guac_mem_ckd_mul() behaves as expected for + * relatively large integer inputs, including inputs that cause overflow beyond + * the capacity of a size_t. + */ +void test_mem__ckd_mul_large() { + + size_t result = 0; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_mul(&result, SIZE_MAX)); + CU_ASSERT_EQUAL(result, SIZE_MAX); + + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_mul(&result, 123, 456, SIZE_MAX)); + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_mul(&result, SIZE_MAX / 2, SIZE_MAX / 2)); + +} + diff --git a/src/libguac/tests/mem/ckd_mul_or_die.c b/src/libguac/tests/mem/ckd_mul_or_die.c new file mode 100644 index 00000000..c4ba7596 --- /dev/null +++ b/src/libguac/tests/mem/ckd_mul_or_die.c @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "assert-signal.h" + +#include +#include +#include + +/** + * Test which verifies that guac_mem_ckd_mul_or_die() calculates zero values + * for all inputs involving at least one zero value. + */ +void test_mem__ckd_mul_or_die_zero() { + + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(0, 0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(0, 0, 0, 0, 0), 0); + + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(0, 1), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(1, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(3, 2, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(5, 0, 8, 9), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(99, 99, 99, 0, 99), 0); + +} + +/** + * Test which verifies that guac_mem_ckd_mul_or_die() successfully calculates + * expected values for relatively small integer inputs. + */ +void test_mem__ckd_mul_or_die_small() { + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(123), 123); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(123, 456), 123 * 456); + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(123, 456, 789), 123 * 456 * 789); +} + +/** + * Test which verifies that guac_mem_ckd_mul_or_die() behaves as expected for + * relatively large integer inputs. + */ +void test_mem__ckd_mul_or_die_large() { + + CU_ASSERT_EQUAL(guac_mem_ckd_mul_or_die(SIZE_MAX), SIZE_MAX); + + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_mul_or_die(123, 456, SIZE_MAX)); + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_mul_or_die(SIZE_MAX / 2, SIZE_MAX / 2)); + +} + diff --git a/src/libguac/tests/mem/ckd_sub.c b/src/libguac/tests/mem/ckd_sub.c new file mode 100644 index 00000000..4dfa01b5 --- /dev/null +++ b/src/libguac/tests/mem/ckd_sub.c @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_mem_ckd_sub() calculates results correctly for + * all inputs involving at least one zero value. + */ +void test_mem__ckd_sub_zero() { + + size_t result = SIZE_MAX; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 0, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 0, 0, 0, 0, 0)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 1, 0)); + CU_ASSERT_EQUAL(result, 1); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 3, 2, 0)); + CU_ASSERT_EQUAL(result, 3 - 2); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 8, 5, 0, 1)); + CU_ASSERT_EQUAL(result, 8 - 5 - 1); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 99, 99, 0)); + CU_ASSERT_EQUAL(result, 0); + +} + +/** + * Test which verifies that guac_mem_ckd_sub() successfully calculates expected + * values for relatively small integer inputs, including inputs that cause + * overflow beyond zero. + */ +void test_mem__ckd_sub_small() { + + size_t result = SIZE_MAX; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 123)); + CU_ASSERT_EQUAL(result, 123); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 456, 123)); + CU_ASSERT_EQUAL(result, 456 - 123); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 789, 456, 123)); + CU_ASSERT_EQUAL(result, 789 - 456 - 123); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, 123, 123)); + CU_ASSERT_EQUAL(result, 0); + + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_sub(&result, 123, 123, 1)); + +} + +/** + * Test which verifies that guac_mem_ckd_sub() behaves as expected for + * relatively large integer inputs, including inputs that cause overflow beyond + * zero. + */ +void test_mem__ckd_sub_large() { + + size_t result = 0; + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, SIZE_MAX)); + CU_ASSERT_EQUAL(result, SIZE_MAX); + + CU_ASSERT_FALSE_FATAL(guac_mem_ckd_sub(&result, SIZE_MAX, SIZE_MAX / 2)); + CU_ASSERT_EQUAL(result, SIZE_MAX - (SIZE_MAX / 2)); + + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_sub(&result, SIZE_MAX, SIZE_MAX, 1)); + CU_ASSERT_TRUE_FATAL(guac_mem_ckd_sub(&result, 0, SIZE_MAX)); + +} + diff --git a/src/libguac/tests/mem/ckd_sub_or_die.c b/src/libguac/tests/mem/ckd_sub_or_die.c new file mode 100644 index 00000000..e29d6c17 --- /dev/null +++ b/src/libguac/tests/mem/ckd_sub_or_die.c @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "assert-signal.h" + +#include +#include +#include + +/** + * Test which verifies that guac_mem_ckd_sub_or_die() calculates results + * correctly for all inputs involving at least one zero value. + */ +void test_mem__ckd_sub_or_die_zero() { + + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(0, 0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(0, 0, 0, 0, 0), 0); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(1, 0), 1); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(3, 2, 0), 3 - 2); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(8, 5, 0, 1), 8 - 5 - 1); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(99, 99, 0), 0); + +} + +/** + * Test which verifies that guac_mem_ckd_sub_or_die() successfully calculates + * expected values for relatively small integer inputs, including inputs that + * cause overflow beyond zero. + */ +void test_mem__ckd_sub_or_die_small() { + + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(123), 123); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(456, 123), 456 - 123); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(789, 456, 123), 789 - 456 - 123); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(123, 123), 0); + + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_sub_or_die(123, 123, 1)); + +} + +/** + * Test which verifies that guac_mem_ckd_sub_or_die() behaves as expected for + * relatively large integer inputs, including inputs that cause overflow beyond + * zero. + */ +void test_mem__ckd_sub_or_die_large() { + + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(SIZE_MAX), SIZE_MAX); + CU_ASSERT_EQUAL(guac_mem_ckd_sub_or_die(SIZE_MAX, SIZE_MAX / 2), SIZE_MAX - (SIZE_MAX / 2)); + + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_sub_or_die(SIZE_MAX, SIZE_MAX, 1)); + ASSERT_SIGNALLED(SIGABRT, guac_mem_ckd_sub_or_die(0, SIZE_MAX)); + +} + diff --git a/src/libguac/tests/mem/free.c b/src/libguac/tests/mem/free.c new file mode 100644 index 00000000..f439b795 --- /dev/null +++ b/src/libguac/tests/mem/free.c @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_mem_free() sets the provided pointer to NULL after + * freeing. + */ +void test_mem__free_assigns_null() { + void* ptr = guac_mem_alloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + CU_ASSERT_PTR_NULL(ptr); +} + +/** + * Test which verifies that guac_mem_free_const() can be used to free constant + * pointers, but that those pointers are not set to NULL after freeing. + */ +void test_mem__free_const() { + const void* ptr = guac_mem_alloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free_const(ptr); + CU_ASSERT_PTR_NOT_NULL(ptr); +} + +/** + * Test which verifies that guac_mem_free() does nothing if provided a NULL + * pointer. + */ +void test_mem__free_null() { + void* ptr = NULL; + guac_mem_free(ptr); +} + +/** + * Test which verifies that guac_mem_free_const() does nothing if provided a NULL + * pointer. + */ +void test_mem__free_null_const() { + const void* ptr = NULL; + guac_mem_free_const(ptr); +} + diff --git a/src/libguac/tests/mem/realloc.c b/src/libguac/tests/mem/realloc.c new file mode 100644 index 00000000..91dbef59 --- /dev/null +++ b/src/libguac/tests/mem/realloc.c @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_mem_realloc() returns NULL for all inputs + * involving at least one zero value (reallocation to zero bytes is not an + * error but equivalent freeing the memory). + */ +void test_mem__realloc_success_zero() { + + void* ptr; + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 0, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 0, 0, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 0, 0, 0, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 1, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 3, 2, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 5, 0, 8, 9)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 99, 99, 99, 0, 99)); + +} + +/** + * Test which verifies that guac_mem_realloc() successfully allocates blocks of + * memory for inputs that can reasonably be expected to succeed. + */ +void test_mem__realloc_success() { + + void* ptr; + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ptr = guac_mem_realloc(ptr, 123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ptr = guac_mem_realloc(ptr, 123, 456); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ptr = guac_mem_realloc(ptr, 123, 456, 789); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + +} + +/** + * Test which verifies that guac_mem_realloc() fails to allocate blocks of + * memory that exceed the capacity of a size_t. + */ +void test_mem__realloc_fail_large() { + + void* ptr; + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, 123, 456, SIZE_MAX)); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc(ptr, SIZE_MAX / 2, SIZE_MAX / 2)); + guac_mem_free(ptr); + +} + diff --git a/src/libguac/tests/mem/zalloc.c b/src/libguac/tests/mem/zalloc.c new file mode 100644 index 00000000..933dca09 --- /dev/null +++ b/src/libguac/tests/mem/zalloc.c @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Test which verifies that guac_mem_zalloc() returns NULL for all inputs involving + * at least one zero value. + */ +void test_mem__zalloc_fail_zero() { + + CU_ASSERT_PTR_NULL(guac_mem_zalloc(0)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(0, 0)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(0, 0, 0, 0)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(0, 0, 0, 0, 0)); + + CU_ASSERT_PTR_NULL(guac_mem_zalloc(1, 0)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(3, 2, 0)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(5, 0, 8, 9)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(99, 99, 99, 0, 99)); + +} + +/** + * Returns whether all bytes within the given memory region are zero. + * + * @param ptr + * The first byte of the memory region to test. + * + * @param length + * The number of bytes within the memory region. + * + * @returns + * Non-zero if all bytes within the memory region have the value of zero, + * zero otherwise. + */ +static int is_all_zeroes(void* ptr, size_t length) { + + int result = 0; + + unsigned char* current = (unsigned char*) ptr; + for (size_t i = 0; i < length; i++) + result |= *(current++); + + return !result; + +} + +/** + * Test which verifies that guac_mem_zalloc() successfully allocates blocks of + * memory for inputs that can reasonably be expected to succeed, and that each + * block is zeroed out. + */ +void test_mem__zalloc_success() { + + void* ptr; + + ptr = guac_mem_zalloc(123); + CU_ASSERT_PTR_NOT_NULL(ptr); + CU_ASSERT(is_all_zeroes(ptr, 123)); + guac_mem_free(ptr); + + ptr = guac_mem_zalloc(123, 456); + CU_ASSERT_PTR_NOT_NULL(ptr); + CU_ASSERT(is_all_zeroes(ptr, 123 * 456)); + guac_mem_free(ptr); + + ptr = guac_mem_zalloc(123, 456, 789); + CU_ASSERT_PTR_NOT_NULL(ptr); + CU_ASSERT(is_all_zeroes(ptr, 123 * 456 * 789)); + guac_mem_free(ptr); + +} + +/** + * Test which verifies that guac_mem_zalloc() fails to allocate blocks of memory + * that exceed the capacity of a size_t. + */ +void test_mem__zalloc_fail_large() { + CU_ASSERT_PTR_NULL(guac_mem_zalloc(123, 456, SIZE_MAX)); + CU_ASSERT_PTR_NULL(guac_mem_zalloc(SIZE_MAX / 2, SIZE_MAX / 2)); +} + From b6d9947c09a392ed128264555d8ae45f9b8239ba Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Wed, 18 Oct 2023 14:58:14 -0700 Subject: [PATCH 02/15] GUACAMOLE-1867: Exclude PRIV_* symbols and private headers from public docs. --- doc/libguac/Doxyfile.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/libguac/Doxyfile.in b/doc/libguac/Doxyfile.in index 5a0ae6bc..d9a5ef7e 100644 --- a/doc/libguac/Doxyfile.in +++ b/doc/libguac/Doxyfile.in @@ -50,7 +50,8 @@ SHOW_INCLUDE_FILES = NO # CASE_SENSE_NAMES = YES -EXCLUDE_SYMBOLS = __* guac_palette* +EXCLUDE_SYMBOLS = __* guac_palette* PRIV_* +EXCLUDE_PATTERNS = **/private/*.h FILE_PATTERNS = *.h INPUT = ../../src/libguac/guacamole JAVADOC_AUTOBRIEF = YES From 0fdc06a9be66ea3b691c4025c6d538a3631da048 Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Fri, 13 Oct 2023 18:22:41 -0700 Subject: [PATCH 03/15] GUACAMOLE-1867: Migrate libguac to new memory management functions. --- src/libguac/argv.c | 5 +- src/libguac/audio.c | 7 +- src/libguac/client.c | 21 +++--- src/libguac/encode-jpeg.c | 7 +- src/libguac/encode-png.c | 9 +-- src/libguac/error.c | 13 ++-- src/libguac/guacamole/string.h | 13 +++- src/libguac/id.c | 5 +- src/libguac/id.h | 11 ++-- src/libguac/palette.c | 6 +- src/libguac/parser.c | 5 +- src/libguac/pool.c | 13 ++-- src/libguac/raw_encoder.c | 14 ++-- src/libguac/raw_encoder.h | 2 +- src/libguac/recording.c | 5 +- src/libguac/socket-broadcast.c | 5 +- src/libguac/socket-fd.c | 5 +- src/libguac/socket-nest.c | 5 +- src/libguac/socket-ssl.c | 7 +- src/libguac/socket-tee.c | 5 +- src/libguac/socket-wsa.c | 5 +- src/libguac/socket.c | 5 +- src/libguac/string.c | 16 ++++- src/libguac/tests/alloc/alloc.c | 73 --------------------- src/libguac/tests/alloc/free.c | 63 ------------------ src/libguac/tests/alloc/size.c | 68 -------------------- src/libguac/tests/alloc/zalloc.c | 102 ------------------------------ src/libguac/tests/id/generate.c | 11 ++-- src/libguac/tests/string/strdup.c | 5 +- src/libguac/user-handlers.c | 19 +++--- src/libguac/user-handshake.c | 5 +- src/libguac/user.c | 26 ++++---- 32 files changed, 152 insertions(+), 409 deletions(-) delete mode 100644 src/libguac/tests/alloc/alloc.c delete mode 100644 src/libguac/tests/alloc/free.c delete mode 100644 src/libguac/tests/alloc/size.c delete mode 100644 src/libguac/tests/alloc/zalloc.c diff --git a/src/libguac/argv.c b/src/libguac/argv.c index b6f2dcb6..98eb49c2 100644 --- a/src/libguac/argv.c +++ b/src/libguac/argv.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/argv.h" #include "guacamole/client.h" #include "guacamole/protocol.h" @@ -273,7 +274,7 @@ static int guac_argv_end_handler(guac_user* user, guac_stream* stream) { pthread_mutex_unlock(&await_state.lock); - free(argv); + guac_mem_free(argv); return 0; } @@ -293,7 +294,7 @@ int guac_argv_received(guac_stream* stream, const char* mimetype, const char* na /* Argument matched */ if (strcmp(state->name, name) == 0) { - guac_argv* argv = malloc(sizeof(guac_argv)); + guac_argv* argv = guac_mem_alloc(sizeof(guac_argv)); guac_strlcpy(argv->mimetype, mimetype, sizeof(argv->mimetype)); argv->state = state; argv->length = 0; diff --git a/src/libguac/audio.c b/src/libguac/audio.c index 0f6a6aad..a3cef3cc 100644 --- a/src/libguac/audio.c +++ b/src/libguac/audio.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/audio.h" #include "guacamole/client.h" #include "guacamole/protocol.h" @@ -113,13 +114,13 @@ guac_audio_stream* guac_audio_stream_alloc(guac_client* client, guac_audio_stream* audio; /* Allocate stream */ - audio = (guac_audio_stream*) calloc(1, sizeof(guac_audio_stream)); + audio = (guac_audio_stream*) guac_mem_zalloc(sizeof(guac_audio_stream)); audio->client = client; audio->stream = guac_client_alloc_stream(client); /* Abort allocation if underlying stream cannot be allocated */ if (audio->stream == NULL) { - free(audio); + guac_mem_free(audio); return NULL; } @@ -198,7 +199,7 @@ void guac_audio_stream_free(guac_audio_stream* audio) { guac_client_free_stream(audio->client, audio->stream); /* Free associated data */ - free(audio); + guac_mem_free(audio); } diff --git a/src/libguac/client.c b/src/libguac/client.c index 2df42edc..a08f3121 100644 --- a/src/libguac/client.c +++ b/src/libguac/client.c @@ -22,6 +22,7 @@ #include "encode-jpeg.h" #include "encode-png.h" #include "encode-webp.h" +#include "guacamole/mem.h" #include "guacamole/client.h" #include "guacamole/error.h" #include "guacamole/layer.h" @@ -84,7 +85,7 @@ const guac_layer* GUAC_DEFAULT_LAYER = &__GUAC_DEFAULT_LAYER; guac_layer* guac_client_alloc_layer(guac_client* client) { /* Init new layer */ - guac_layer* allocd_layer = malloc(sizeof(guac_layer)); + guac_layer* allocd_layer = guac_mem_alloc(sizeof(guac_layer)); allocd_layer->index = guac_pool_next_int(client->__layer_pool)+1; return allocd_layer; @@ -94,7 +95,7 @@ guac_layer* guac_client_alloc_layer(guac_client* client) { guac_layer* guac_client_alloc_buffer(guac_client* client) { /* Init new layer */ - guac_layer* allocd_layer = malloc(sizeof(guac_layer)); + guac_layer* allocd_layer = guac_mem_alloc(sizeof(guac_layer)); allocd_layer->index = -guac_pool_next_int(client->__buffer_pool) - 1; return allocd_layer; @@ -107,7 +108,7 @@ void guac_client_free_buffer(guac_client* client, guac_layer* layer) { guac_pool_free_int(client->__buffer_pool, -layer->index - 1); /* Free layer */ - free(layer); + guac_mem_free(layer); } @@ -117,7 +118,7 @@ void guac_client_free_layer(guac_client* client, guac_layer* layer) { guac_pool_free_int(client->__layer_pool, layer->index); /* Free layer */ - free(layer); + guac_mem_free(layer); } @@ -255,7 +256,7 @@ guac_client* guac_client_alloc() { int i; /* Allocate new client */ - guac_client* client = malloc(sizeof(guac_client)); + guac_client* client = guac_mem_alloc(sizeof(guac_client)); if (client == NULL) { guac_error = GUAC_STATUS_NO_MEMORY; guac_error_message = "Could not allocate memory for client"; @@ -272,7 +273,7 @@ guac_client* guac_client_alloc() { /* Generate ID */ client->connection_id = guac_generate_id(GUAC_CLIENT_ID_PREFIX); if (client->connection_id == NULL) { - free(client); + guac_mem_free(client); return NULL; } @@ -284,7 +285,7 @@ guac_client* guac_client_alloc() { client->__stream_pool = guac_pool_alloc(0); /* Initialize streams */ - client->__output_streams = malloc(sizeof(guac_stream) * GUAC_CLIENT_MAX_STREAMS); + client->__output_streams = guac_mem_alloc(sizeof(guac_stream), GUAC_CLIENT_MAX_STREAMS); for (i=0; i__output_streams[i].index = GUAC_CLIENT_CLOSED_STREAM_INDEX; @@ -346,7 +347,7 @@ void guac_client_free(guac_client* client) { guac_pool_free(client->__layer_pool); /* Free streams */ - free(client->__output_streams); + guac_mem_free(client->__output_streams); /* Free stream pool */ guac_pool_free(client->__stream_pool); @@ -374,8 +375,8 @@ void guac_client_free(guac_client* client) { guac_rwlock_destroy(&(client->__users_lock)); guac_rwlock_destroy(&(client->__pending_users_lock)); - free(client->connection_id); - free(client); + guac_mem_free(client->connection_id); + guac_mem_free(client); } void vguac_client_log(guac_client* client, guac_client_log_level level, diff --git a/src/libguac/encode-jpeg.c b/src/libguac/encode-jpeg.c index 8e145d86..65d8ceae 100644 --- a/src/libguac/encode-jpeg.c +++ b/src/libguac/encode-jpeg.c @@ -20,6 +20,7 @@ #include "config.h" #include "encode-jpeg.h" +#include "guacamole/mem.h" #include "guacamole/error.h" #include "guacamole/protocol.h" #include "guacamole/stream.h" @@ -211,9 +212,7 @@ int guac_jpeg_write(guac_socket* socket, guac_stream* stream, /* Create a buffer for the write scan line which is where we will * put the converted pixels (BGRx -> RGB) */ - int write_stride = cinfo.image_width * cinfo.input_components; - unsigned char *scanline_data = malloc(write_stride); - memset(scanline_data, 0, write_stride); + unsigned char *scanline_data = guac_mem_zalloc(cinfo.image_width, cinfo.input_components); #endif /* Initialize the JPEG compressor */ @@ -254,7 +253,7 @@ int guac_jpeg_write(guac_socket* socket, guac_stream* stream, } #ifndef JCS_EXTENSIONS - free(scanline_data); + guac_mem_free(scanline_data); #endif /* Finalize compression */ diff --git a/src/libguac/encode-png.c b/src/libguac/encode-png.c index 20d2f5de..e930c058 100644 --- a/src/libguac/encode-png.c +++ b/src/libguac/encode-png.c @@ -20,6 +20,7 @@ #include "config.h" #include "encode-png.h" +#include "guacamole/mem.h" #include "guacamole/error.h" #include "guacamole/protocol.h" #include "guacamole/stream.h" @@ -342,11 +343,11 @@ int guac_png_write(guac_socket* socket, guac_stream* stream, guac_png_flush_handler); /* Copy data from surface into PNG data */ - png_rows = (png_byte**) malloc(sizeof(png_byte*) * height); + png_rows = (png_byte**) guac_mem_alloc(sizeof(png_byte*), height); for (y=0; y @@ -176,24 +177,24 @@ static pthread_once_t __guac_error_key_init = PTHREAD_ONCE_INIT; static pthread_key_t __guac_error_message_key; static pthread_once_t __guac_error_message_key_init = PTHREAD_ONCE_INIT; -static void __guac_free_pointer(void* pointer) { +static void __guac_mem_free_pointer(void* pointer) { /* Free memory allocated to status variable */ - free(pointer); + guac_mem_free(pointer); } static void __guac_alloc_error_key() { /* Create key, destroy any allocated variable on thread exit */ - pthread_key_create(&__guac_error_key, __guac_free_pointer); + pthread_key_create(&__guac_error_key, __guac_mem_free_pointer); } static void __guac_alloc_error_message_key() { /* Create key, destroy any allocated variable on thread exit */ - pthread_key_create(&__guac_error_message_key, __guac_free_pointer); + pthread_key_create(&__guac_error_message_key, __guac_mem_free_pointer); } @@ -210,7 +211,7 @@ guac_status* __guac_error() { /* Allocate thread-local status variable if not already allocated */ if (status == NULL) { - status = malloc(sizeof(guac_status)); + status = guac_mem_alloc(sizeof(guac_status)); pthread_setspecific(__guac_error_key, status); } @@ -234,7 +235,7 @@ const char** __guac_error_message() { /* Allocate thread-local message variable if not already allocated */ if (message == NULL) { - message = malloc(sizeof(const char*)); + message = guac_mem_alloc(sizeof(const char*)); pthread_setspecific(__guac_error_message_key, message); } diff --git a/src/libguac/guacamole/string.h b/src/libguac/guacamole/string.h index f720ba19..27bf7b10 100644 --- a/src/libguac/guacamole/string.h +++ b/src/libguac/guacamole/string.h @@ -132,8 +132,17 @@ size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n); char* guac_strnstr(const char *haystack, const char *needle, size_t len); /** - * Simple wrapper for strdup() which behaves identically to standard strdup(), - * except that NULL will be returned if the provided string is NULL. + * Duplicates the given string, returning a newly-allocated string containing + * the same contents. The provided string must be null-terminated. The size of + * the memory block for the newly-allocated string is only guaranteed to + * include enough space for the contents of the provided string, including null + * terminator. + * + * The pointer returned by guac_strdup() SHOULD be freed with a subsequent call + * to guac_mem_free(), but MAY instead be freed with a subsequent call to free(). + * + * This function behaves identically to standard strdup(), except that NULL + * will be returned if the provided string is NULL. * * @param str * The string to duplicate as a newly-allocated string. diff --git a/src/libguac/id.c b/src/libguac/id.c index e627f89d..75cde962 100644 --- a/src/libguac/id.c +++ b/src/libguac/id.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/error.h" #include "id.h" @@ -68,7 +69,7 @@ char* guac_generate_id(char prefix) { #endif /* Allocate buffer for future formatted ID */ - buffer = malloc(GUAC_UUID_LEN + 2); + buffer = guac_mem_alloc(GUAC_UUID_LEN + 2); if (buffer == NULL) { #ifndef HAVE_LIBUUID uuid_destroy(uuid); @@ -86,7 +87,7 @@ char* guac_generate_id(char prefix) { #else size_t identifier_length = GUAC_UUID_LEN + 1; if (uuid_export(uuid, UUID_FMT_STR, &identifier, &identifier_length) != UUID_RC_OK) { - free(buffer); + guac_mem_free(buffer); uuid_destroy(uuid); guac_error = GUAC_STATUS_INTERNAL_ERROR; guac_error_message = "Conversion of UUID to unique ID failed"; diff --git a/src/libguac/id.h b/src/libguac/id.h index 9b64d410..4a54cdbf 100644 --- a/src/libguac/id.h +++ b/src/libguac/id.h @@ -23,13 +23,16 @@ /** * Generates a guaranteed-unique identifier which is a total of 37 characters * long, having the given single-character prefix. The resulting identifier - * must be freed with a call to free() when no longer needed. If an error + * must be freed with a call to guac_mem_free() when no longer needed. If an error * occurs, NULL is returned, no memory is allocated, and guac_error is set * appropriately. * - * @param prefix The single-character prefix to use. - * @return A newly-allocated unique identifier with the given prefix, or - * NULL if the identifier could not be generated. + * @param prefix + * The single-character prefix to use. + * + * @return + * A newly-allocated unique identifier with the given prefix, or NULL if + * the identifier could not be generated. */ char* guac_generate_id(char prefix); diff --git a/src/libguac/palette.c b/src/libguac/palette.c index 16f97010..1c56d828 100644 --- a/src/libguac/palette.c +++ b/src/libguac/palette.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "palette.h" #include @@ -38,8 +39,7 @@ guac_palette* guac_palette_alloc(cairo_surface_t* surface) { unsigned char* data = cairo_image_surface_get_data(surface); /* Allocate palette */ - guac_palette* palette = (guac_palette*) malloc(sizeof(guac_palette)); - memset(palette, 0, sizeof(guac_palette)); + guac_palette* palette = (guac_palette*) guac_mem_zalloc(sizeof(guac_palette)); for (y=0; y @@ -26,7 +27,7 @@ guac_pool* guac_pool_alloc(int size) { pthread_mutexattr_t lock_attributes; - guac_pool* pool = malloc(sizeof(guac_pool)); + guac_pool* pool = guac_mem_alloc(sizeof(guac_pool)); /* If unable to allocate, just return NULL. */ if (pool == NULL) @@ -57,14 +58,14 @@ void guac_pool_free(guac_pool* pool) { guac_pool_int* old = current; current = current->__next; - free(old); + guac_mem_free(old); } /* Destroy lock */ pthread_mutex_destroy(&(pool->__lock)); /* Free pool */ - free(pool); + guac_mem_free(pool); } @@ -89,7 +90,7 @@ int guac_pool_next_int(guac_pool* pool) { /* If only one element exists, reset pool to empty. */ if (pool->__tail == pool->__head) { - free(pool->__head); + guac_mem_free(pool->__head); pool->__head = NULL; pool->__tail = NULL; } @@ -98,7 +99,7 @@ int guac_pool_next_int(guac_pool* pool) { else { guac_pool_int* old_head = pool->__head; pool->__head = old_head->__next; - free(old_head); + guac_mem_free(old_head); } /* Return retrieved value. */ @@ -109,7 +110,7 @@ int guac_pool_next_int(guac_pool* pool) { void guac_pool_free_int(guac_pool* pool, int value) { /* Allocate and initialize new returned value */ - guac_pool_int* pool_int = malloc(sizeof(guac_pool_int)); + guac_pool_int* pool_int = guac_mem_alloc(sizeof(guac_pool_int)); pool_int->value = value; pool_int->__next = NULL; diff --git a/src/libguac/raw_encoder.c b/src/libguac/raw_encoder.c index 888bde79..8fdefc75 100644 --- a/src/libguac/raw_encoder.c +++ b/src/libguac/raw_encoder.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/audio.h" #include "guacamole/client.h" #include "guacamole/protocol.h" @@ -52,13 +53,12 @@ static void raw_encoder_begin_handler(guac_audio_stream* audio) { raw_encoder_send_audio(audio, audio->client->socket); /* Allocate and init encoder state */ - audio->data = state = malloc(sizeof(raw_encoder_state)); + audio->data = state = guac_mem_alloc(sizeof(raw_encoder_state)); state->written = 0; - state->length = GUAC_RAW_ENCODER_BUFFER_SIZE - * audio->rate * audio->channels * audio->bps - / 8 / 1000; + state->length = guac_mem_ckd_mul_or_die(GUAC_RAW_ENCODER_BUFFER_SIZE, + audio->rate, audio->channels, audio->bps) / 8 / 1000; - state->buffer = malloc(state->length); + state->buffer = guac_mem_alloc(state->length); } @@ -78,8 +78,8 @@ static void raw_encoder_end_handler(guac_audio_stream* audio) { guac_protocol_send_end(audio->client->socket, audio->stream); /* Free state information */ - free(state->buffer); - free(state); + guac_mem_free(state->buffer); + guac_mem_free(state); } diff --git a/src/libguac/raw_encoder.h b/src/libguac/raw_encoder.h index c3af151c..e60d12b4 100644 --- a/src/libguac/raw_encoder.h +++ b/src/libguac/raw_encoder.h @@ -52,7 +52,7 @@ typedef struct raw_encoder_state { /** * Size of the PCM buffer, in bytes. */ - int length; + size_t length; /** * The current number of bytes stored within the PCM buffer. diff --git a/src/libguac/recording.c b/src/libguac/recording.c index 0fd94284..7544cc14 100644 --- a/src/libguac/recording.c +++ b/src/libguac/recording.c @@ -17,6 +17,7 @@ * under the License. */ +#include "guacamole/mem.h" #include "guacamole/client.h" #include "guacamole/protocol.h" #include "guacamole/recording.h" @@ -162,7 +163,7 @@ guac_recording* guac_recording_create(guac_client* client, } /* Create recording structure with reference to underlying socket */ - guac_recording* recording = malloc(sizeof(guac_recording)); + guac_recording* recording = guac_mem_alloc(sizeof(guac_recording)); recording->socket = guac_socket_open(fd); recording->include_output = include_output; recording->include_mouse = include_mouse; @@ -191,7 +192,7 @@ void guac_recording_free(guac_recording* recording) { guac_socket_free(recording->socket); /* Free recording itself */ - free(recording); + guac_mem_free(recording); } diff --git a/src/libguac/socket-broadcast.c b/src/libguac/socket-broadcast.c index 49f6672e..2d605fea 100644 --- a/src/libguac/socket-broadcast.c +++ b/src/libguac/socket-broadcast.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/client.h" #include "guacamole/error.h" #include "guacamole/socket.h" @@ -360,7 +361,7 @@ static int __guac_socket_broadcast_free_handler(guac_socket* socket) { /* Destroy locks */ pthread_mutex_destroy(&(data->socket_lock)); - free(data); + guac_mem_free(data); return 0; } @@ -387,7 +388,7 @@ static guac_socket* __guac_socket_init( /* Allocate socket and associated data */ guac_socket* socket = guac_socket_alloc(); guac_socket_broadcast_data* data = - malloc(sizeof(guac_socket_broadcast_data)); + guac_mem_alloc(sizeof(guac_socket_broadcast_data)); /* Set the provided broadcast handler */ data->broadcast_handler = broadcast_handler; diff --git a/src/libguac/socket-fd.c b/src/libguac/socket-fd.c index 742cc35d..44f45e2e 100644 --- a/src/libguac/socket-fd.c +++ b/src/libguac/socket-fd.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/error.h" #include "guacamole/socket.h" #include "wait-fd.h" @@ -382,7 +383,7 @@ static int guac_socket_fd_free_handler(guac_socket* socket) { /* Close file descriptor */ close(data->fd); - free(data); + guac_mem_free(data); return 0; } @@ -423,7 +424,7 @@ guac_socket* guac_socket_open(int fd) { /* Allocate socket and associated data */ guac_socket* socket = guac_socket_alloc(); - guac_socket_fd_data* data = malloc(sizeof(guac_socket_fd_data)); + guac_socket_fd_data* data = guac_mem_alloc(sizeof(guac_socket_fd_data)); /* Store file descriptor as socket data */ data->fd = fd; diff --git a/src/libguac/socket-nest.c b/src/libguac/socket-nest.c index 8bc9291e..29319097 100644 --- a/src/libguac/socket-nest.c +++ b/src/libguac/socket-nest.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/protocol.h" #include "guacamole/socket.h" #include "guacamole/unicode.h" @@ -274,7 +275,7 @@ static int guac_socket_nest_free_handler(guac_socket* socket) { /* Free associated data */ guac_socket_nest_data* data = (guac_socket_nest_data*) socket->data; - free(data); + guac_mem_free(data); return 0; @@ -314,7 +315,7 @@ guac_socket* guac_socket_nest(guac_socket* parent, int index) { /* Allocate socket and associated data */ guac_socket* socket = guac_socket_alloc(); - guac_socket_nest_data* data = malloc(sizeof(guac_socket_nest_data)); + guac_socket_nest_data* data = guac_mem_alloc(sizeof(guac_socket_nest_data)); /* Store nested socket details as socket data */ data->parent = parent; diff --git a/src/libguac/socket-ssl.c b/src/libguac/socket-ssl.c index 3daa128e..2825a357 100644 --- a/src/libguac/socket-ssl.c +++ b/src/libguac/socket-ssl.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/error.h" #include "guacamole/socket-ssl.h" #include "guacamole/socket.h" @@ -96,7 +97,7 @@ static int __guac_socket_ssl_free_handler(guac_socket* socket) { /* Close file descriptor */ close(data->fd); - free(data); + guac_mem_free(data); return 0; } @@ -109,7 +110,7 @@ guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd) { /* Allocate socket and associated data */ guac_socket* socket = guac_socket_alloc(); - guac_socket_ssl_data* data = malloc(sizeof(guac_socket_ssl_data)); + guac_socket_ssl_data* data = guac_mem_alloc(sizeof(guac_socket_ssl_data)); /* Init SSL */ data->context = context; @@ -122,7 +123,7 @@ guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd) { guac_error = GUAC_STATUS_INTERNAL_ERROR; guac_error_message = "SSL accept failed"; - free(data); + guac_mem_free(data); guac_socket_free(socket); SSL_free(ssl); return NULL; diff --git a/src/libguac/socket-tee.c b/src/libguac/socket-tee.c index cee9108c..84710455 100644 --- a/src/libguac/socket-tee.c +++ b/src/libguac/socket-tee.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/socket.h" #include @@ -202,7 +203,7 @@ static int __guac_socket_tee_free_handler(guac_socket* socket) { guac_socket_free(data->secondary); /* Freeing the tee socket always succeeds */ - free(data); + guac_mem_free(data); return 0; } @@ -210,7 +211,7 @@ static int __guac_socket_tee_free_handler(guac_socket* socket) { guac_socket* guac_socket_tee(guac_socket* primary, guac_socket* secondary) { /* Set up socket to split outout into a file */ - guac_socket_tee_data* data = malloc(sizeof(guac_socket_tee_data)); + guac_socket_tee_data* data = guac_mem_alloc(sizeof(guac_socket_tee_data)); data->primary = primary; data->secondary = secondary; diff --git a/src/libguac/socket-wsa.c b/src/libguac/socket-wsa.c index f5602e39..18e79475 100644 --- a/src/libguac/socket-wsa.c +++ b/src/libguac/socket-wsa.c @@ -17,6 +17,7 @@ * under the License. */ +#include "guacamole/mem.h" #include "guacamole/error.h" #include "guacamole/socket.h" @@ -378,7 +379,7 @@ static int guac_socket_wsa_free_handler(guac_socket* socket) { /* Close socket */ closesocket(data->sock); - free(data); + guac_mem_free(data); return 0; } @@ -419,7 +420,7 @@ guac_socket* guac_socket_open_wsa(SOCKET sock) { /* Allocate socket and associated data */ guac_socket* socket = guac_socket_alloc(); - guac_socket_wsa_data* data = malloc(sizeof(guac_socket_wsa_data)); + guac_socket_wsa_data* data = guac_mem_alloc(sizeof(guac_socket_wsa_data)); /* Store socket as socket data */ data->sock = sock; diff --git a/src/libguac/socket.c b/src/libguac/socket.c index c435ad55..e0e01fef 100644 --- a/src/libguac/socket.c +++ b/src/libguac/socket.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/error.h" #include "guacamole/protocol.h" #include "guacamole/socket.h" @@ -141,7 +142,7 @@ int guac_socket_select(guac_socket* socket, int usec_timeout) { guac_socket* guac_socket_alloc() { - guac_socket* socket = malloc(sizeof(guac_socket)); + guac_socket* socket = guac_mem_alloc(sizeof(guac_socket)); /* If no memory available, return with error */ if (socket == NULL) { @@ -213,7 +214,7 @@ void guac_socket_free(guac_socket* socket) { pthread_join(socket->__keep_alive_thread, NULL); } - free(socket); + guac_mem_free(socket); } ssize_t guac_socket_write_int(guac_socket* socket, int64_t i) { diff --git a/src/libguac/string.c b/src/libguac/string.c index 260465da..2a7ec2cd 100644 --- a/src/libguac/string.c +++ b/src/libguac/string.c @@ -19,6 +19,8 @@ #include "config.h" +#include "guacamole/mem.h" + #include #include @@ -119,8 +121,18 @@ char* guac_strdup(const char* str) { if (str == NULL) return NULL; - /* Otherwise just invoke strdup() */ - return strdup(str); + /* Do not attempt to duplicate if the length is somehow magically so + * obscenely large that it will not be possible to add a null terminator */ + size_t length; + if (guac_mem_ckd_add(&length, strlen(str), 1)) + return NULL; + + /* Otherwise just copy to a new string in same manner as strdup() */ + void* new_str = guac_mem_alloc(length); + if (new_str != NULL) + memcpy(new_str, str, length); + + return new_str; } diff --git a/src/libguac/tests/alloc/alloc.c b/src/libguac/tests/alloc/alloc.c deleted file mode 100644 index edb1f000..00000000 --- a/src/libguac/tests/alloc/alloc.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include - -/** - * Test which verifies that guac_alloc() returns NULL for all inputs involving - * at least one zero value. - */ -void test_alloc__alloc_fail_zero() { - - CU_ASSERT_PTR_NULL(guac_alloc(0)); - CU_ASSERT_PTR_NULL(guac_alloc(0, 0)); - CU_ASSERT_PTR_NULL(guac_alloc(0, 0, 0)); - CU_ASSERT_PTR_NULL(guac_alloc(0, 0, 0, 0)); - CU_ASSERT_PTR_NULL(guac_alloc(0, 0, 0, 0, 0)); - - CU_ASSERT_PTR_NULL(guac_alloc(1, 0)); - CU_ASSERT_PTR_NULL(guac_alloc(3, 2, 0)); - CU_ASSERT_PTR_NULL(guac_alloc(5, 0, 8, 9)); - CU_ASSERT_PTR_NULL(guac_alloc(99, 99, 99, 0, 99)); - -} - -/** - * Test which verifies that guac_alloc() successfully allocates blocks of - * memory for inputs that can reasonably be expected to succeed. - */ -void test_alloc__alloc_success() { - - void* ptr; - - ptr = guac_alloc(123); - CU_ASSERT_PTR_NOT_NULL(ptr); - guac_free(ptr); - - ptr = guac_alloc(123, 456); - CU_ASSERT_PTR_NOT_NULL(ptr); - guac_free(ptr); - - ptr = guac_alloc(123, 456, 789); - CU_ASSERT_PTR_NOT_NULL(ptr); - guac_free(ptr); - -} - -/** - * Test which verifies that guac_alloc() fails to allocate blocks of memory - * that exceed the capacity of a size_t. - */ -void test_alloc__alloc_fail_large() { - CU_ASSERT_PTR_NULL(guac_alloc(123, 456, SIZE_MAX)); - CU_ASSERT_PTR_NULL(guac_alloc(SIZE_MAX / 2, SIZE_MAX / 2)); -} - diff --git a/src/libguac/tests/alloc/free.c b/src/libguac/tests/alloc/free.c deleted file mode 100644 index 3a055d3d..00000000 --- a/src/libguac/tests/alloc/free.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include - -/** - * Test which verifies that guac_free() sets the provided pointer to NULL after - * freeing. - */ -void test_alloc__free_assigns_null() { - void* ptr = guac_alloc(123); - CU_ASSERT_PTR_NOT_NULL(ptr); - guac_free(ptr); - CU_ASSERT_PTR_NULL(ptr); -} - -/** - * Test which verifies that guac_free_const() can be used to free constant - * pointers, but that those pointers are not set to NULL after freeing. - */ -void test_alloc__free_const() { - const void* ptr = guac_alloc(123); - CU_ASSERT_PTR_NOT_NULL(ptr); - guac_free_const(ptr); - CU_ASSERT_PTR_NOT_NULL(ptr); -} - -/** - * Test which verifies that guac_free() does nothing if provided a NULL - * pointer. - */ -void test_alloc__free_null() { - void* ptr = NULL; - guac_free(ptr); -} - -/** - * Test which verifies that guac_free_const() does nothing if provided a NULL - * pointer. - */ -void test_alloc__free_null_const() { - const void* ptr = NULL; - guac_free_const(ptr); -} - diff --git a/src/libguac/tests/alloc/size.c b/src/libguac/tests/alloc/size.c deleted file mode 100644 index d2be0a2e..00000000 --- a/src/libguac/tests/alloc/size.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include - -/** - * Test which verifies that guac_alloc_size() returns zero for all inputs - * involving at least one zero value. - */ -void test_alloc__size_zero() { - - CU_ASSERT_EQUAL(guac_alloc_size(0), 0); - CU_ASSERT_EQUAL(guac_alloc_size(0, 0), 0); - CU_ASSERT_EQUAL(guac_alloc_size(0, 0, 0), 0); - CU_ASSERT_EQUAL(guac_alloc_size(0, 0, 0, 0), 0); - CU_ASSERT_EQUAL(guac_alloc_size(0, 0, 0, 0, 0), 0); - - CU_ASSERT_EQUAL(guac_alloc_size(1, 0), 0); - CU_ASSERT_EQUAL(guac_alloc_size(3, 2, 0), 0); - CU_ASSERT_EQUAL(guac_alloc_size(5, 0, 8, 9), 0); - CU_ASSERT_EQUAL(guac_alloc_size(99, 99, 99, 0, 99), 0); - -} - -/** - * Test which verifies that guac_alloc_size() returns expected values for - * relatively small integer inputs. - */ -void test_alloc__size_small() { - - CU_ASSERT_EQUAL(guac_alloc_size(123), 123); - CU_ASSERT_EQUAL(guac_alloc_size(123, 456), 123 * 456); - CU_ASSERT_EQUAL(guac_alloc_size(123, 456, 789), 123 * 456 * 789); - -} - -/** - * Test which verifies that guac_alloc_size() returns expected values for - * relatively large integer inputs, including inputs that cause overflow - * beyond the capacity of a size_t. - */ -void test_alloc__size_large() { - - CU_ASSERT_EQUAL(guac_alloc_size(SIZE_MAX), SIZE_MAX); - - CU_ASSERT_EQUAL(guac_alloc_size(123, 456, SIZE_MAX), 0); - CU_ASSERT_EQUAL(guac_alloc_size(SIZE_MAX / 2, SIZE_MAX / 2), 0); - -} - diff --git a/src/libguac/tests/alloc/zalloc.c b/src/libguac/tests/alloc/zalloc.c deleted file mode 100644 index 5209921d..00000000 --- a/src/libguac/tests/alloc/zalloc.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include - -/** - * Test which verifies that guac_zalloc() returns NULL for all inputs involving - * at least one zero value. - */ -void test_alloc__zalloc_fail_zero() { - - CU_ASSERT_PTR_NULL(guac_zalloc(0)); - CU_ASSERT_PTR_NULL(guac_zalloc(0, 0)); - CU_ASSERT_PTR_NULL(guac_zalloc(0, 0, 0)); - CU_ASSERT_PTR_NULL(guac_zalloc(0, 0, 0, 0)); - CU_ASSERT_PTR_NULL(guac_zalloc(0, 0, 0, 0, 0)); - - CU_ASSERT_PTR_NULL(guac_zalloc(1, 0)); - CU_ASSERT_PTR_NULL(guac_zalloc(3, 2, 0)); - CU_ASSERT_PTR_NULL(guac_zalloc(5, 0, 8, 9)); - CU_ASSERT_PTR_NULL(guac_zalloc(99, 99, 99, 0, 99)); - -} - -/** - * Returns whether all bytes within the given memory region are zero. - * - * @param ptr - * The first byte of the memory region to test. - * - * @param length - * The number of bytes within the memory region. - * - * @returns - * Non-zero if all bytes within the memory region have the value of zero, - * zero otherwise. - */ -static int is_all_zeroes(void* ptr, size_t length) { - - int result = 0; - - unsigned char* current = (unsigned char*) ptr; - for (size_t i = 0; i < length; i++) - result |= *(current++); - - return !result; - -} - -/** - * Test which verifies that guac_zalloc() successfully allocates blocks of - * memory for inputs that can reasonably be expected to succeed, and that each - * block is zeroed out. - */ -void test_alloc__zalloc_success() { - - void* ptr; - - ptr = guac_zalloc(123); - CU_ASSERT_PTR_NOT_NULL(ptr); - CU_ASSERT(is_all_zeroes(ptr, 123)); - guac_free(ptr); - - ptr = guac_zalloc(123, 456); - CU_ASSERT_PTR_NOT_NULL(ptr); - CU_ASSERT(is_all_zeroes(ptr, 123 * 456)); - guac_free(ptr); - - ptr = guac_zalloc(123, 456, 789); - CU_ASSERT_PTR_NOT_NULL(ptr); - CU_ASSERT(is_all_zeroes(ptr, 123 * 456 * 789)); - guac_free(ptr); - -} - -/** - * Test which verifies that guac_zalloc() fails to allocate blocks of memory - * that exceed the capacity of a size_t. - */ -void test_alloc__zalloc_fail_large() { - CU_ASSERT_PTR_NULL(guac_zalloc(123, 456, SIZE_MAX)); - CU_ASSERT_PTR_NULL(guac_zalloc(SIZE_MAX / 2, SIZE_MAX / 2)); -} - diff --git a/src/libguac/tests/id/generate.c b/src/libguac/tests/id/generate.c index 3142a6f1..31c336a7 100644 --- a/src/libguac/tests/id/generate.c +++ b/src/libguac/tests/id/generate.c @@ -17,6 +17,7 @@ * under the License. */ +#include "guacamole/mem.h" #include "id.h" #include @@ -40,8 +41,8 @@ void test_id__unique() { /* Both strings should be different */ CU_ASSERT_STRING_NOT_EQUAL(id1, id2); - free(id1); - free(id2); + guac_mem_free(id1); + guac_mem_free(id2); } @@ -62,7 +63,7 @@ void test_id__format() { CU_ASSERT_EQUAL(items_read, 6); CU_ASSERT_EQUAL(strlen(id), 37); - free(id); + guac_mem_free(id); } @@ -77,12 +78,12 @@ void test_id__prefix() { id = guac_generate_id('a'); CU_ASSERT_PTR_NOT_NULL_FATAL(id); CU_ASSERT_EQUAL(id[0], 'a'); - free(id); + guac_mem_free(id); id = guac_generate_id('b'); CU_ASSERT_PTR_NOT_NULL_FATAL(id); CU_ASSERT_EQUAL(id[0], 'b'); - free(id); + guac_mem_free(id); } diff --git a/src/libguac/tests/string/strdup.c b/src/libguac/tests/string/strdup.c index 0b1e76b3..9641e093 100644 --- a/src/libguac/tests/string/strdup.c +++ b/src/libguac/tests/string/strdup.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -46,4 +47,6 @@ void test_string__strdup() { CU_ASSERT_STRING_EQUAL(dest_string, "Mashing avocados."); CU_ASSERT_PTR_NULL(null_copy); -} \ No newline at end of file + guac_mem_free(dest_string); + +} diff --git a/src/libguac/user-handlers.c b/src/libguac/user-handlers.c index db1e7b8b..1dfef55f 100644 --- a/src/libguac/user-handlers.c +++ b/src/libguac/user-handlers.c @@ -19,10 +19,12 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/client.h" #include "guacamole/object.h" #include "guacamole/protocol.h" #include "guacamole/stream.h" +#include "guacamole/string.h" #include "guacamole/timestamp.h" #include "guacamole/user.h" #include "user-handlers.h" @@ -680,11 +682,11 @@ int __guac_handshake_image_handler(guac_user* user, int argc, char** argv) { int __guac_handshake_name_handler(guac_user* user, int argc, char** argv) { /* Free any past value for the user's name */ - free((char *) user->info.name); + guac_mem_free_const(user->info.name); /* If a value is provided for the name, copy it into guac_user. */ if (argc > 0 && strcmp(argv[0], "")) - user->info.name = (const char*) strdup(argv[0]); + user->info.name = (const char*) guac_strdup(argv[0]); /* No or empty value was provided, so make sure this is NULLed out. */ else @@ -697,11 +699,11 @@ int __guac_handshake_name_handler(guac_user* user, int argc, char** argv) { int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) { /* Free any past value */ - free((char *) user->info.timezone); + guac_mem_free_const(user->info.timezone); /* Store timezone, if present */ if (argc > 0 && strcmp(argv[0], "")) - user->info.timezone = (const char*) strdup(argv[0]); + user->info.timezone = (const char*) guac_strdup(argv[0]); else user->info.timezone = NULL; @@ -715,11 +717,12 @@ char** guac_copy_mimetypes(char** mimetypes, int count) { int i; /* Allocate sufficient space for NULL-terminated array of mimetypes */ - char** mimetypes_copy = malloc(sizeof(char*) * (count+1)); + char** mimetypes_copy = guac_mem_alloc(sizeof(char*), + guac_mem_ckd_add_or_die(count, 1)); /* Copy each provided mimetype */ for (i = 0; i < count; i++) - mimetypes_copy[i] = strdup(mimetypes[i]); + mimetypes_copy[i] = guac_strdup(mimetypes[i]); /* Terminate with NULL */ mimetypes_copy[count] = NULL; @@ -737,12 +740,12 @@ void guac_free_mimetypes(char** mimetypes) { /* Free all strings within NULL-terminated mimetype array */ while (*current_mimetype != NULL) { - free(*current_mimetype); + guac_mem_free(*current_mimetype); current_mimetype++; } /* Free the array itself, now that its contents have been freed */ - free(mimetypes); + guac_mem_free(mimetypes); } diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index 0863325f..422c941b 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -19,6 +19,7 @@ #include "config.h" +#include "guacamole/mem.h" #include "guacamole/client.h" #include "guacamole/error.h" #include "guacamole/parser.h" @@ -372,8 +373,8 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_free_mimetypes((char **) user->info.video_mimetypes); /* Free name and timezone info. */ - free((char *) user->info.name); - free((char *) user->info.timezone); + guac_mem_free_const(user->info.name); + guac_mem_free_const(user->info.timezone); guac_parser_free(parser); diff --git a/src/libguac/user.c b/src/libguac/user.c index d16f43b9..ba681967 100644 --- a/src/libguac/user.c +++ b/src/libguac/user.c @@ -22,12 +22,14 @@ #include "encode-jpeg.h" #include "encode-png.h" #include "encode-webp.h" +#include "guacamole/mem.h" #include "guacamole/client.h" #include "guacamole/object.h" #include "guacamole/pool.h" #include "guacamole/protocol.h" #include "guacamole/socket.h" #include "guacamole/stream.h" +#include "guacamole/string.h" #include "guacamole/timestamp.h" #include "guacamole/user.h" #include "id.h" @@ -40,13 +42,13 @@ guac_user* guac_user_alloc() { - guac_user* user = calloc(1, sizeof(guac_user)); + guac_user* user = guac_mem_zalloc(sizeof(guac_user)); int i; /* Generate ID */ user->user_id = guac_generate_id(GUAC_USER_ID_PREFIX); if (user->user_id == NULL) { - free(user); + guac_mem_free(user); return NULL; } @@ -59,8 +61,8 @@ guac_user* guac_user_alloc() { user->__stream_pool = guac_pool_alloc(0); /* Initialze streams */ - user->__input_streams = malloc(sizeof(guac_stream) * GUAC_USER_MAX_STREAMS); - user->__output_streams = malloc(sizeof(guac_stream) * GUAC_USER_MAX_STREAMS); + user->__input_streams = guac_mem_alloc(sizeof(guac_stream), GUAC_USER_MAX_STREAMS); + user->__output_streams = guac_mem_alloc(sizeof(guac_stream), GUAC_USER_MAX_STREAMS); for (i=0; i__input_streams[i].index = GUAC_USER_CLOSED_STREAM_INDEX; @@ -71,7 +73,7 @@ guac_user* guac_user_alloc() { user->__object_pool = guac_pool_alloc(0); /* Initialize objects */ - user->__objects = malloc(sizeof(guac_object) * GUAC_USER_MAX_OBJECTS); + user->__objects = guac_mem_alloc(sizeof(guac_object), GUAC_USER_MAX_OBJECTS); for (i=0; i__objects[i].index = GUAC_USER_UNDEFINED_OBJECT_INDEX; @@ -82,21 +84,21 @@ guac_user* guac_user_alloc() { void guac_user_free(guac_user* user) { /* Free streams */ - free(user->__input_streams); - free(user->__output_streams); + guac_mem_free(user->__input_streams); + guac_mem_free(user->__output_streams); /* Free stream pool */ guac_pool_free(user->__stream_pool); /* Free objects */ - free(user->__objects); + guac_mem_free(user->__objects); /* Free object pool */ guac_pool_free(user->__object_pool); /* Clean up user */ - free(user->user_id); - free(user); + guac_mem_free(user->user_id); + guac_mem_free(user); } @@ -377,12 +379,12 @@ char* guac_user_parse_args_string(guac_user* user, const char** arg_names, guac_user_log(user, GUAC_LOG_DEBUG, "Parameter \"%s\" omitted. Using " "default value of \"%s\".", arg_names[index], default_value); - return strdup(default_value); + return guac_strdup(default_value); } /* Otherwise use provided value */ - return strdup(value); + return guac_strdup(value); } From afba5488ba1d43f31f07907d7ef2c0e2718b1e4a Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Fri, 20 Oct 2023 13:37:57 -0700 Subject: [PATCH 04/15] GUACAMOLE-1867: Migrate guacd to new memory management functions. --- src/guacd/conf-args.c | 23 +++++++++++++---------- src/guacd/conf-file.c | 32 +++++++++++++++++--------------- src/guacd/connection.c | 11 ++++++----- src/guacd/daemon.c | 9 +++++---- src/guacd/proc-map.c | 5 +++-- src/guacd/proc.c | 13 +++++++------ 6 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/guacd/conf-args.c b/src/guacd/conf-args.c index 239eb3ae..c4509737 100644 --- a/src/guacd/conf-args.c +++ b/src/guacd/conf-args.c @@ -23,6 +23,9 @@ #include "conf-args.h" #include "conf-parse.h" +#include +#include + #include #include #include @@ -36,14 +39,14 @@ int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) { /* -l: Bind port */ if (opt == 'l') { - free(config->bind_port); - config->bind_port = strdup(optarg); + guac_mem_free(config->bind_port); + config->bind_port = guac_strdup(optarg); } /* -b: Bind host */ else if (opt == 'b') { - free(config->bind_host); - config->bind_host = strdup(optarg); + guac_mem_free(config->bind_host); + config->bind_host = guac_strdup(optarg); } /* -f: Run in foreground */ @@ -58,8 +61,8 @@ int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) { /* -p: PID file */ else if (opt == 'p') { - free(config->pidfile); - config->pidfile = strdup(optarg); + guac_mem_free(config->pidfile); + config->pidfile = guac_strdup(optarg); } /* -L: Log level */ @@ -79,14 +82,14 @@ int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) { #ifdef ENABLE_SSL /* -C SSL certificate */ else if (opt == 'C') { - free(config->cert_file); - config->cert_file = strdup(optarg); + guac_mem_free(config->cert_file); + config->cert_file = guac_strdup(optarg); } /* -K SSL key */ else if (opt == 'K') { - free(config->key_file); - config->key_file = strdup(optarg); + guac_mem_free(config->key_file); + config->key_file = guac_strdup(optarg); } #else else if (opt == 'C' || opt == 'K') { diff --git a/src/guacd/conf-file.c b/src/guacd/conf-file.c index 1f1e5669..ed74dcbc 100644 --- a/src/guacd/conf-file.c +++ b/src/guacd/conf-file.c @@ -24,6 +24,8 @@ #include "conf-parse.h" #include +#include +#include #include #include @@ -48,15 +50,15 @@ static int guacd_conf_callback(const char* section, const char* param, const cha /* Bind host */ if (strcmp(param, "bind_host") == 0) { - free(config->bind_host); - config->bind_host = strdup(value); + guac_mem_free(config->bind_host); + config->bind_host = guac_strdup(value); return 0; } /* Bind port */ else if (strcmp(param, "bind_port") == 0) { - free(config->bind_port); - config->bind_port = strdup(value); + guac_mem_free(config->bind_port); + config->bind_port = guac_strdup(value); return 0; } @@ -67,8 +69,8 @@ static int guacd_conf_callback(const char* section, const char* param, const cha /* PID file */ if (strcmp(param, "pid_file") == 0) { - free(config->pidfile); - config->pidfile = strdup(value); + guac_mem_free(config->pidfile); + config->pidfile = guac_strdup(value); return 0; } @@ -96,15 +98,15 @@ static int guacd_conf_callback(const char* section, const char* param, const cha #ifdef ENABLE_SSL /* SSL certificate */ if (strcmp(param, "server_certificate") == 0) { - free(config->cert_file); - config->cert_file = strdup(value); + guac_mem_free(config->cert_file); + config->cert_file = guac_strdup(value); return 0; } /* SSL key */ else if (strcmp(param, "server_key") == 0) { - free(config->key_file); - config->key_file = strdup(value); + guac_mem_free(config->key_file); + config->key_file = guac_strdup(value); return 0; } #else @@ -171,13 +173,13 @@ int guacd_conf_parse_file(guacd_config* conf, int fd) { guacd_config* guacd_conf_load() { - guacd_config* conf = malloc(sizeof(guacd_config)); + guacd_config* conf = guac_mem_alloc(sizeof(guacd_config)); if (conf == NULL) return NULL; /* Load defaults */ - conf->bind_host = strdup(GUACD_DEFAULT_BIND_HOST); - conf->bind_port = strdup(GUACD_DEFAULT_BIND_PORT); + conf->bind_host = guac_strdup(GUACD_DEFAULT_BIND_HOST); + conf->bind_port = guac_strdup(GUACD_DEFAULT_BIND_PORT); conf->pidfile = NULL; conf->foreground = 0; conf->print_version = 0; @@ -197,7 +199,7 @@ guacd_config* guacd_conf_load() { if (retval != 0) { fprintf(stderr, "Unable to parse \"" GUACD_CONF_FILE "\".\n"); - free(conf); + guac_mem_free(conf); return NULL; } @@ -206,7 +208,7 @@ guacd_config* guacd_conf_load() { /* Notify of errors preventing reading */ else if (errno != ENOENT) { fprintf(stderr, "Unable to open \"" GUACD_CONF_FILE "\": %s\n", strerror(errno)); - free(conf); + guac_mem_free(conf); return NULL; } diff --git a/src/guacd/connection.c b/src/guacd/connection.c index 1bb99dc0..2c8c00d6 100644 --- a/src/guacd/connection.c +++ b/src/guacd/connection.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -151,7 +152,7 @@ void* guacd_connection_io_thread(void* data) { /* Clean up */ guac_socket_free(params->socket); close(params->fd); - free(params); + guac_mem_free(params); return NULL; @@ -202,7 +203,7 @@ static int guacd_add_user(guacd_proc* proc, guac_parser* parser, guac_socket* so /* Close our end of the process file descriptor */ close(proc_fd); - guacd_connection_io_thread_params* params = malloc(sizeof(guacd_connection_io_thread_params)); + guacd_connection_io_thread_params* params = guac_mem_alloc(sizeof(guacd_connection_io_thread_params)); params->parser = parser; params->socket = socket; params->fd = user_fd; @@ -353,7 +354,7 @@ static int guacd_route_connection(guacd_proc_map* map, guac_socket* socket) { /* Clean up */ close(proc->fd_socket); - free(proc); + guac_mem_free(proc); } @@ -381,7 +382,7 @@ void* guacd_connection_thread(void* data) { if (socket == NULL) { guacd_log_guac_error(GUAC_LOG_ERROR, "Unable to set up SSL/TLS"); close(connected_socket_fd); - free(params); + guac_mem_free(params); return NULL; } } @@ -397,7 +398,7 @@ void* guacd_connection_thread(void* data) { if (guacd_route_connection(map, socket)) guac_socket_free(socket); - free(params); + guac_mem_free(params); return NULL; } diff --git a/src/guacd/daemon.c b/src/guacd/daemon.c index e867ada5..33184e36 100644 --- a/src/guacd/daemon.c +++ b/src/guacd/daemon.c @@ -26,6 +26,8 @@ #include "log.h" #include "proc-map.h" +#include + #ifdef ENABLE_SSL #include #endif @@ -212,8 +214,7 @@ static void guacd_openssl_init_locks(int count) { int i; /* Allocate required number of locks */ - guacd_openssl_locks = - malloc(sizeof(pthread_mutex_t) * count); + guacd_openssl_locks = guac_mem_alloc(sizeof(pthread_mutex_t), count); /* Initialize each lock */ for (i=0; i < count; i++) @@ -240,7 +241,7 @@ static void guacd_openssl_free_locks(int count) { pthread_mutex_destroy(&(guacd_openssl_locks[i])); /* Free lock array */ - free(guacd_openssl_locks); + guac_mem_free(guacd_openssl_locks); } #endif @@ -532,7 +533,7 @@ int main(int argc, char* argv[]) { } /* Create parameters for connection thread */ - guacd_connection_thread_params* params = malloc(sizeof(guacd_connection_thread_params)); + guacd_connection_thread_params* params = guac_mem_alloc(sizeof(guacd_connection_thread_params)); if (params == NULL) { guacd_log(GUAC_LOG_ERROR, "Could not create connection thread: %s", strerror(errno)); continue; diff --git a/src/guacd/proc-map.c b/src/guacd/proc-map.c index 73a9daeb..ea5f2e9a 100644 --- a/src/guacd/proc-map.c +++ b/src/guacd/proc-map.c @@ -23,6 +23,7 @@ #include "proc-map.h" #include +#include #include #include @@ -129,7 +130,7 @@ static guac_common_list_element* __guacd_proc_find(guac_common_list* bucket, guacd_proc_map* guacd_proc_map_alloc() { - guacd_proc_map* map = malloc(sizeof(guacd_proc_map)); + guacd_proc_map* map = guac_mem_alloc(sizeof(guacd_proc_map)); map->processes = guac_common_list_alloc(); guac_common_list** current; @@ -160,7 +161,7 @@ int guacd_proc_map_add(guacd_proc_map* map, guacd_proc* proc) { /* If no such element, we can add the new client successfully */ if (found == NULL) { - guacd_proc_map_entry* entry = malloc(sizeof(guacd_proc_map_entry)); + guacd_proc_map_entry* entry = guac_mem_alloc(sizeof(guacd_proc_map_entry)); guac_common_list_lock(map->processes); entry->element = guac_common_list_add(map->processes, proc); diff --git a/src/guacd/proc.c b/src/guacd/proc.c index 9325575d..28ccac1c 100644 --- a/src/guacd/proc.c +++ b/src/guacd/proc.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -106,7 +107,7 @@ static void* guacd_user_thread(void* data) { /* Clean up */ guac_socket_free(socket); guac_user_free(user); - free(params); + guac_mem_free(params); return NULL; @@ -130,7 +131,7 @@ static void* guacd_user_thread(void* data) { */ static void guacd_proc_add_user(guacd_proc* proc, int fd, int owner) { - guacd_user_thread_params* params = malloc(sizeof(guacd_user_thread_params)); + guacd_user_thread_params* params = guac_mem_alloc(sizeof(guacd_user_thread_params)); params->proc = proc; params->fd = fd; params->owner = owner; @@ -409,7 +410,7 @@ cleanup_process: /* Free up all internal resources outside the client */ close(proc->fd_socket); - free(proc); + guac_mem_free(proc); exit(result); @@ -429,7 +430,7 @@ guacd_proc* guacd_create_proc(const char* protocol) { int child_socket = sockets[1]; /* Allocate process */ - guacd_proc* proc = calloc(1, sizeof(guacd_proc)); + guacd_proc* proc = guac_mem_zalloc(sizeof(guacd_proc)); if (proc == NULL) { close(parent_socket); close(child_socket); @@ -442,7 +443,7 @@ guacd_proc* guacd_create_proc(const char* protocol) { guacd_log_guac_error(GUAC_LOG_ERROR, "Unable to create client"); close(parent_socket); close(child_socket); - free(proc); + guac_mem_free(proc); return NULL; } @@ -456,7 +457,7 @@ guacd_proc* guacd_create_proc(const char* protocol) { close(parent_socket); close(child_socket); guac_client_free(proc->client); - free(proc); + guac_mem_free(proc); return NULL; } From e4057c218994591c9e35c189ea4fc886d0e509ce Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Fri, 20 Oct 2023 13:56:26 -0700 Subject: [PATCH 05/15] GUACAMOLE-1867: Migrate common convenience library to new memory management functions. --- src/common/clipboard.c | 10 ++++++---- src/common/common/cursor.h | 2 +- src/common/common/string.h | 32 ++++++++++++++++++++++---------- src/common/cursor.c | 17 +++++++++-------- src/common/display.c | 15 ++++++++------- src/common/list.c | 12 +++++++----- src/common/string.c | 21 ++++++++++++--------- src/common/surface.c | 33 +++++++++++++++++---------------- src/common/tests/Makefile.am | 3 ++- src/common/tests/string/split.c | 13 +++++++------ 10 files changed, 91 insertions(+), 67 deletions(-) diff --git a/src/common/clipboard.c b/src/common/clipboard.c index f9bf1acb..72ec263d 100644 --- a/src/common/clipboard.c +++ b/src/common/clipboard.c @@ -21,6 +21,7 @@ #include "common/clipboard.h" #include +#include #include #include #include @@ -31,11 +32,11 @@ guac_common_clipboard* guac_common_clipboard_alloc() { - guac_common_clipboard* clipboard = malloc(sizeof(guac_common_clipboard)); + guac_common_clipboard* clipboard = guac_mem_alloc(sizeof(guac_common_clipboard)); /* Init clipboard */ clipboard->mimetype[0] = '\0'; - clipboard->buffer = malloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH); + clipboard->buffer = guac_mem_alloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH); clipboard->available = GUAC_COMMON_CLIPBOARD_MAX_LENGTH; clipboard->length = 0; @@ -51,10 +52,11 @@ void guac_common_clipboard_free(guac_common_clipboard* clipboard) { pthread_mutex_destroy(&(clipboard->lock)); /* Free buffer */ - free(clipboard->buffer); + guac_mem_free(clipboard->buffer); /* Free base structure */ - free(clipboard); + guac_mem_free(clipboard); + } /** diff --git a/src/common/common/cursor.h b/src/common/common/cursor.h index 133176a7..aca24faa 100644 --- a/src/common/common/cursor.h +++ b/src/common/common/cursor.h @@ -68,7 +68,7 @@ typedef struct guac_common_cursor { /** * The size of the image data buffer, in bytes. */ - int image_buffer_size; + size_t image_buffer_size; /** * The current cursor image, if any. If the mouse cursor has not yet been diff --git a/src/common/common/string.h b/src/common/common/string.h index 442d7f49..8498cddc 100644 --- a/src/common/common/string.h +++ b/src/common/common/string.h @@ -22,24 +22,36 @@ #include "config.h" +#include + /** * Counts the number of occurrences of a given character in a string. * - * @param string The string to count occurrences within. - * @param c The character to count occurrences of. - * @return The number of occurrences. + * @param string + * The string to count occurrences within. + * + * @param c + * The character to count occurrences of. + * + * @return + * The number of occurrences. */ -int guac_count_occurrences(const char* string, char c); +size_t guac_count_occurrences(const char* string, char c); /** * Splits a string into a newly-allocated array of strings. The array itself - * and each string within the array will eventually need to be freed. The array - * is NULL-terminated. + * and each string within the array will eventually need to be freed through + * calls to guac_mem_free(). The array is NULL-terminated. * - * @param string The string to split. - * @param delim The character which separates individual substrings within the - * given string. - * @return A newly-allocated, NULL-terminated array of strings. + * @param string + * The string to split. + * + * @param delim + * The character which separates individual substrings within the + * given string. + * + * @return + * A newly-allocated, NULL-terminated array of strings. */ char** guac_split(const char* string, char delim); diff --git a/src/common/cursor.c b/src/common/cursor.c index 881ea15b..2a1650fd 100644 --- a/src/common/cursor.c +++ b/src/common/cursor.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,7 @@ */ guac_common_cursor* guac_common_cursor_alloc(guac_client* client) { - guac_common_cursor* cursor = malloc(sizeof(guac_common_cursor)); + guac_common_cursor* cursor = guac_mem_alloc(sizeof(guac_common_cursor)); if (cursor == NULL) return NULL; @@ -58,7 +59,7 @@ guac_common_cursor* guac_common_cursor_alloc(guac_client* client) { /* Allocate initial image buffer */ cursor->image_buffer_size = GUAC_COMMON_CURSOR_DEFAULT_SIZE; - cursor->image_buffer = malloc(cursor->image_buffer_size); + cursor->image_buffer = guac_mem_alloc(cursor->image_buffer_size); /* No cursor image yet */ cursor->width = 0; @@ -90,7 +91,7 @@ void guac_common_cursor_free(guac_common_cursor* cursor) { cairo_surface_t* surface = cursor->surface; /* Free image buffer and surface */ - free(cursor->image_buffer); + guac_mem_free(cursor->image_buffer); if (surface != NULL) cairo_surface_destroy(surface); @@ -100,7 +101,7 @@ void guac_common_cursor_free(guac_common_cursor* cursor) { /* Return buffer to pool */ guac_client_free_buffer(client, buffer); - free(cursor); + guac_mem_free(cursor); } @@ -206,17 +207,17 @@ void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user, static void guac_common_cursor_resize(guac_common_cursor* cursor, int width, int height, int stride) { - int minimum_size = height * stride; + size_t minimum_size = guac_mem_ckd_mul_or_die(height, stride); /* Grow image buffer if necessary */ if (cursor->image_buffer_size < minimum_size) { /* Calculate new size */ - cursor->image_buffer_size = minimum_size*2; + cursor->image_buffer_size = guac_mem_ckd_mul_or_die(minimum_size, 2); /* Destructively reallocate image buffer */ - free(cursor->image_buffer); - cursor->image_buffer = malloc(cursor->image_buffer_size); + guac_mem_free(cursor->image_buffer); + cursor->image_buffer = guac_mem_alloc(cursor->image_buffer_size); } diff --git a/src/common/display.c b/src/common/display.c index 0fddb9b0..9e884430 100644 --- a/src/common/display.c +++ b/src/common/display.c @@ -22,6 +22,7 @@ #include "common/surface.h" #include +#include #include #include @@ -92,7 +93,7 @@ static void guac_common_display_free_layers(guac_common_display_layer* layers, guac_client_free_layer(client, layer); /* Free current element and advance to next */ - free(current); + guac_mem_free(current); current = next; } @@ -119,14 +120,14 @@ guac_common_display* guac_common_display_alloc(guac_client* client, int width, int height) { /* Allocate display */ - guac_common_display* display = malloc(sizeof(guac_common_display)); + guac_common_display* display = guac_mem_alloc(sizeof(guac_common_display)); if (display == NULL) return NULL; /* Allocate shared cursor */ display->cursor = guac_common_cursor_alloc(client); if (display->cursor == NULL) { - free(display); + guac_mem_free(display); return NULL; } @@ -159,7 +160,7 @@ void guac_common_display_free(guac_common_display* display) { guac_common_display_free_layers(display->layers, display->client); pthread_mutex_destroy(&display->_lock); - free(display); + guac_mem_free(display); } @@ -252,7 +253,7 @@ static guac_common_display_layer* guac_common_display_add_layer( guac_common_display_layer* old_head = *head; guac_common_display_layer* display_layer = - malloc(sizeof(guac_common_display_layer)); + guac_mem_alloc(sizeof(guac_common_display_layer)); /* Init layer/surface pair */ display_layer->layer = layer; @@ -361,7 +362,7 @@ void guac_common_display_free_layer(guac_common_display* display, guac_client_free_layer(display->client, display_layer->layer); /* Free list element */ - free(display_layer); + guac_mem_free(display_layer); pthread_mutex_unlock(&display->_lock); @@ -380,7 +381,7 @@ void guac_common_display_free_buffer(guac_common_display* display, guac_client_free_buffer(display->client, display_buffer->layer); /* Free list element */ - free(display_buffer); + guac_mem_free(display_buffer); pthread_mutex_unlock(&display->_lock); diff --git a/src/common/list.c b/src/common/list.c index 4138d3cc..f1012437 100644 --- a/src/common/list.c +++ b/src/common/list.c @@ -20,12 +20,14 @@ #include "config.h" #include "common/list.h" +#include + #include #include guac_common_list* guac_common_list_alloc() { - guac_common_list* list = malloc(sizeof(guac_common_list)); + guac_common_list* list = guac_mem_alloc(sizeof(guac_common_list)); pthread_mutex_init(&list->_lock, NULL); list->head = NULL; @@ -47,12 +49,12 @@ void guac_common_list_free( if (free_element_handler != NULL) free_element_handler(element->data); - free(element); + guac_mem_free(element); element = next; } /* Free the list itself */ - free(list); + guac_mem_free(list); } @@ -61,7 +63,7 @@ guac_common_list_element* guac_common_list_add(guac_common_list* list, /* Allocate element, initialize as new head */ guac_common_list_element* element = - malloc(sizeof(guac_common_list_element)); + guac_mem_alloc(sizeof(guac_common_list_element)); element->data = data; element->next = list->head; element->_ptr = &(list->head); @@ -85,7 +87,7 @@ void guac_common_list_remove(guac_common_list* list, if (element->next != NULL) element->next->_ptr = element->_ptr; - free(element); + guac_mem_free(element); } diff --git a/src/common/string.c b/src/common/string.c index b2479998..87bfff5c 100644 --- a/src/common/string.c +++ b/src/common/string.c @@ -21,18 +21,20 @@ #include "common/string.h" +#include + #include #include -int guac_count_occurrences(const char* string, char c) { +size_t guac_count_occurrences(const char* string, char c) { - int count = 0; + size_t count = 0; while (*string != 0) { /* Count each occurrence */ if (*string == c) - count++; + count = guac_mem_ckd_add_or_die(count, 1); /* Next character */ string++; @@ -45,17 +47,18 @@ int guac_count_occurrences(const char* string, char c) { char** guac_split(const char* string, char delim) { - int i = 0; + size_t i = 0; - int token_count = guac_count_occurrences(string, delim) + 1; + /* Calculate number of tokens present based on number of delimiters */ + size_t token_count = guac_mem_ckd_add_or_die(guac_count_occurrences(string, delim), 1); const char* token_start = string; - /* Allocate space for tokens */ - char** tokens = malloc(sizeof(char*) * (token_count+1)); + /* Allocate space for tokens, including NULL terminator */ + char** tokens = guac_mem_alloc(sizeof(char*), guac_mem_ckd_add_or_die(token_count, 1)); do { - int length; + size_t length; char* token; /* Find end of token */ @@ -66,7 +69,7 @@ char** guac_split(const char* string, char delim) { length = string - token_start; /* Allocate space for token and NULL terminator */ - tokens[i++] = token = malloc(length + 1); + tokens[i++] = token = guac_mem_alloc(guac_mem_ckd_add_or_die(length, 1)); /* Copy token, store null */ memcpy(token, token_start, length); diff --git a/src/common/surface.c b/src/common/surface.c index e5d1ca9f..9334f0ce 100644 --- a/src/common/surface.c +++ b/src/common/surface.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -396,7 +397,7 @@ static unsigned int __guac_common_surface_calculate_framerate( int x, y; /* Calculate heat map dimensions */ - int heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(surface->width); + size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(surface->width); /* Calculate minimum X/Y coordinates intersecting given rect */ int min_x = rect->x / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; @@ -615,7 +616,7 @@ static void __guac_common_surface_touch_rect(guac_common_surface* surface, int x, y; /* Calculate heat map dimensions */ - int heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(surface->width); + size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(surface->width); /* Calculate minimum X/Y coordinates intersecting given rect */ int min_x = rect->x / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; @@ -1227,11 +1228,11 @@ guac_common_surface* guac_common_surface_alloc(guac_client* client, guac_socket* socket, const guac_layer* layer, int w, int h) { /* Calculate heat map dimensions */ - int heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(w); - int heat_height = GUAC_COMMON_SURFACE_HEAT_DIMENSION(h); + size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(w); + size_t heat_height = GUAC_COMMON_SURFACE_HEAT_DIMENSION(h); /* Init surface */ - guac_common_surface* surface = calloc(1, sizeof(guac_common_surface)); + guac_common_surface* surface = guac_mem_zalloc(sizeof(guac_common_surface)); surface->client = client; surface->socket = socket; surface->layer = layer; @@ -1244,10 +1245,10 @@ guac_common_surface* guac_common_surface_alloc(guac_client* client, /* Create corresponding Cairo surface */ surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); - surface->buffer = calloc(h, surface->stride); + surface->buffer = guac_mem_zalloc(h, surface->stride); /* Create corresponding heat map */ - surface->heat_map = calloc(heat_width * heat_height, + surface->heat_map = guac_mem_zalloc(heat_width, heat_height, sizeof(guac_common_surface_heat_cell)); /* Reset clipping rect */ @@ -1274,9 +1275,9 @@ void guac_common_surface_free(guac_common_surface* surface) { pthread_mutex_destroy(&surface->_lock); - free(surface->heat_map); - free(surface->buffer); - free(surface); + guac_mem_free(surface->heat_map); + guac_mem_free(surface->buffer); + guac_mem_free(surface); } @@ -1299,8 +1300,8 @@ void guac_common_surface_resize(guac_common_surface* surface, int w, int h) { int sy = 0; /* Calculate heat map dimensions */ - int heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(w); - int heat_height = GUAC_COMMON_SURFACE_HEAT_DIMENSION(h); + size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(w); + size_t heat_height = GUAC_COMMON_SURFACE_HEAT_DIMENSION(h); /* Copy old surface data */ old_buffer = surface->buffer; @@ -1311,7 +1312,7 @@ void guac_common_surface_resize(guac_common_surface* surface, int w, int h) { surface->width = w; surface->height = h; surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); - surface->buffer = calloc(h, surface->stride); + surface->buffer = guac_mem_zalloc(h, surface->stride); __guac_common_bound_rect(surface, &surface->clip_rect, NULL, NULL); /* Copy relevant old data */ @@ -1319,11 +1320,11 @@ void guac_common_surface_resize(guac_common_surface* surface, int w, int h) { __guac_common_surface_put(old_buffer, old_stride, &sx, &sy, surface, &old_rect, 1); /* Free old data */ - free(old_buffer); + guac_mem_free(old_buffer); /* Allocate completely new heat map (can safely discard old stats) */ - free(surface->heat_map); - surface->heat_map = calloc(heat_width * heat_height, + guac_mem_free(surface->heat_map); + surface->heat_map = guac_mem_alloc(heat_width, heat_height, sizeof(guac_common_surface_heat_cell)); /* Resize dirty rect to fit new surface dimensions */ diff --git a/src/common/tests/Makefile.am b/src/common/tests/Makefile.am index 526577b2..4c26f1cf 100644 --- a/src/common/tests/Makefile.am +++ b/src/common/tests/Makefile.am @@ -50,7 +50,8 @@ test_common_SOURCES = \ test_common_CFLAGS = \ -Werror -Wall -pedantic \ - @COMMON_INCLUDE@ + @COMMON_INCLUDE@ \ + @LIBGUAC_INCLUDE@ test_common_LDADD = \ @COMMON_LTLIB@ \ diff --git a/src/common/tests/string/split.c b/src/common/tests/string/split.c index 36f8f191..d7740188 100644 --- a/src/common/tests/string/split.c +++ b/src/common/tests/string/split.c @@ -20,6 +20,7 @@ #include "common/string.h" #include +#include #include @@ -52,12 +53,12 @@ void test_string__split() { CU_ASSERT_PTR_NULL(tokens[5]); /* Clean up */ - free(tokens[0]); - free(tokens[1]); - free(tokens[2]); - free(tokens[3]); - free(tokens[4]); - free(tokens); + guac_mem_free(tokens[0]); + guac_mem_free(tokens[1]); + guac_mem_free(tokens[2]); + guac_mem_free(tokens[3]); + guac_mem_free(tokens[4]); + guac_mem_free(tokens); } From dfb708498d1286c6e6403b47e08587109670bfce Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Sat, 14 Oct 2023 01:44:41 -0700 Subject: [PATCH 06/15] GUACAMOLE-1867: Migrate VNC to new memory management functions. --- src/protocols/vnc/argv.c | 12 ++++++---- src/protocols/vnc/client.c | 5 ++-- src/protocols/vnc/cursor.c | 5 ++-- src/protocols/vnc/display.c | 5 ++-- src/protocols/vnc/settings.c | 45 ++++++++++++++++++------------------ 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/protocols/vnc/argv.c b/src/protocols/vnc/argv.c index e59b1de7..44fe5ee0 100644 --- a/src/protocols/vnc/argv.c +++ b/src/protocols/vnc/argv.c @@ -21,8 +21,10 @@ #include "argv.h" #include "vnc.h" +#include #include #include +#include #include #include @@ -38,16 +40,16 @@ int guac_vnc_argv_callback(guac_user* user, const char* mimetype, /* Update username */ if (strcmp(name, GUAC_VNC_ARGV_USERNAME) == 0) { - free(settings->username); - settings->username = strdup(value); + guac_mem_free(settings->username); + settings->username = guac_strdup(value); } /* Update password */ else if (strcmp(name, GUAC_VNC_ARGV_PASSWORD) == 0) { - free(settings->password); - settings->password = strdup(value); + guac_mem_free(settings->password); + settings->password = guac_strdup(value); } return 0; -} \ No newline at end of file +} diff --git a/src/protocols/vnc/client.c b/src/protocols/vnc/client.c index ea7d44b3..43ead098 100644 --- a/src/protocols/vnc/client.c +++ b/src/protocols/vnc/client.c @@ -34,6 +34,7 @@ #endif #include +#include #include #include @@ -102,7 +103,7 @@ int guac_client_init(guac_client* client) { client->args = GUAC_VNC_CLIENT_ARGS; /* Alloc client data */ - guac_vnc_client* vnc_client = calloc(1, sizeof(guac_vnc_client)); + guac_vnc_client* vnc_client = guac_mem_zalloc(sizeof(guac_vnc_client)); client->data = vnc_client; #ifdef ENABLE_VNC_TLS_LOCKING @@ -209,7 +210,7 @@ int guac_vnc_client_free_handler(guac_client* client) { #endif /* Free generic data struct */ - free(client->data); + guac_mem_free(client->data); return 0; } diff --git a/src/protocols/vnc/cursor.c b/src/protocols/vnc/cursor.c index 22d45ebe..bd013f55 100644 --- a/src/protocols/vnc/cursor.c +++ b/src/protocols/vnc/cursor.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,7 @@ void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int bpp) { /* Cairo image buffer */ int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); - unsigned char* buffer = malloc(h*stride); + unsigned char* buffer = guac_mem_alloc(h, stride); unsigned char* buffer_row_current = buffer; /* VNC image buffer */ @@ -120,7 +121,7 @@ void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int bpp) { buffer, w, h, stride); /* Free surface */ - free(buffer); + guac_mem_free(buffer); /* libvncclient does not free rcMask as it does rcSource */ free(client->rcMask); diff --git a/src/protocols/vnc/display.c b/src/protocols/vnc/display.c index 7273e4b3..8848e893 100644 --- a/src/protocols/vnc/display.c +++ b/src/protocols/vnc/display.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,7 @@ void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) { /* Init Cairo buffer */ stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w); - buffer = malloc(h*stride); + buffer = guac_mem_alloc(h, stride); buffer_row_current = buffer; bpp = client->format.bitsPerPixel/8; @@ -134,7 +135,7 @@ void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) { /* Free surface */ cairo_surface_destroy(surface); - free(buffer); + guac_mem_free(buffer); } diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index a476b2c1..a7171128 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -24,6 +24,7 @@ #include "common/defaults.h" #include "settings.h" +#include #include #include @@ -395,7 +396,7 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user, return NULL; } - guac_vnc_settings* settings = calloc(1, sizeof(guac_vnc_settings)); + guac_vnc_settings* settings = guac_mem_zalloc(sizeof(guac_vnc_settings)); settings->hostname = guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, @@ -646,43 +647,43 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user, void guac_vnc_settings_free(guac_vnc_settings* settings) { /* Free settings strings */ - free(settings->clipboard_encoding); - free(settings->encodings); - free(settings->hostname); - free(settings->password); - free(settings->recording_name); - free(settings->recording_path); - free(settings->username); + guac_mem_free(settings->clipboard_encoding); + guac_mem_free(settings->encodings); + guac_mem_free(settings->hostname); + guac_mem_free(settings->password); + guac_mem_free(settings->recording_name); + guac_mem_free(settings->recording_path); + guac_mem_free(settings->username); #ifdef ENABLE_VNC_REPEATER /* Free VNC repeater settings */ - free(settings->dest_host); + guac_mem_free(settings->dest_host); #endif #ifdef ENABLE_COMMON_SSH /* Free SFTP settings */ - free(settings->sftp_directory); - free(settings->sftp_root_directory); - free(settings->sftp_host_key); - free(settings->sftp_hostname); - free(settings->sftp_passphrase); - free(settings->sftp_password); - free(settings->sftp_port); - free(settings->sftp_private_key); - free(settings->sftp_username); + guac_mem_free(settings->sftp_directory); + guac_mem_free(settings->sftp_root_directory); + guac_mem_free(settings->sftp_host_key); + guac_mem_free(settings->sftp_hostname); + guac_mem_free(settings->sftp_passphrase); + guac_mem_free(settings->sftp_password); + guac_mem_free(settings->sftp_port); + guac_mem_free(settings->sftp_private_key); + guac_mem_free(settings->sftp_username); #endif #ifdef ENABLE_PULSE /* Free PulseAudio settings */ - free(settings->pa_servername); + guac_mem_free(settings->pa_servername); #endif /* Free Wake-on-LAN strings */ - free(settings->wol_mac_addr); - free(settings->wol_broadcast_addr); + guac_mem_free(settings->wol_mac_addr); + guac_mem_free(settings->wol_broadcast_addr); /* Free settings structure */ - free(settings); + guac_mem_free(settings); } From f0811575041a62466cdc46945f5058e19c0bf78f Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Sun, 15 Oct 2023 14:08:58 -0700 Subject: [PATCH 07/15] GUACAMOLE-1867: Migrate RDP to new memory management functions. --- src/protocols/rdp/argv.c | 16 ++-- src/protocols/rdp/beep.c | 7 +- .../rdp/channels/audio-input/audio-buffer.c | 28 +++---- .../rdp/channels/audio-input/audio-buffer.h | 4 +- src/protocols/rdp/channels/cliprdr.c | 11 +-- src/protocols/rdp/channels/common-svc.c | 5 +- src/protocols/rdp/channels/disp.c | 5 +- src/protocols/rdp/channels/pipe-svc.c | 5 +- .../rdp/channels/rdpdr/rdpdr-fs-messages.c | 5 +- src/protocols/rdp/channels/rdpdr/rdpdr.c | 5 +- src/protocols/rdp/channels/rdpei.c | 5 +- src/protocols/rdp/channels/rdpsnd/rdpsnd.c | 6 +- src/protocols/rdp/client.c | 5 +- src/protocols/rdp/download.c | 11 +-- src/protocols/rdp/fs.c | 17 +++-- src/protocols/rdp/glyph.c | 5 +- src/protocols/rdp/keyboard.c | 5 +- src/protocols/rdp/ls.c | 5 +- src/protocols/rdp/plugins/channels.c | 3 +- .../plugins/guac-common-svc/guac-common-svc.c | 3 +- src/protocols/rdp/plugins/guacai/guacai.c | 13 ++-- src/protocols/rdp/print-job.c | 7 +- src/protocols/rdp/rdp.c | 7 +- src/protocols/rdp/settings.c | 75 ++++++++++--------- src/protocols/rdp/tests/fs/normalize_path.c | 20 ++--- src/protocols/rdp/upload.c | 7 +- 26 files changed, 156 insertions(+), 129 deletions(-) diff --git a/src/protocols/rdp/argv.c b/src/protocols/rdp/argv.c index c6c922b9..16080d91 100644 --- a/src/protocols/rdp/argv.c +++ b/src/protocols/rdp/argv.c @@ -22,8 +22,10 @@ #include "rdp.h" #include "settings.h" +#include #include #include +#include #include #include @@ -39,22 +41,22 @@ int guac_rdp_argv_callback(guac_user* user, const char* mimetype, /* Update username */ if (strcmp(name, GUAC_RDP_ARGV_USERNAME) == 0) { - free(settings->username); - settings->username = strdup(value); + guac_mem_free(settings->username); + settings->username = guac_strdup(value); } /* Update password */ else if (strcmp(name, GUAC_RDP_ARGV_PASSWORD) == 0) { - free(settings->password); - settings->password = strdup(value); + guac_mem_free(settings->password); + settings->password = guac_strdup(value); } /* Update domain */ else if (strcmp(name, GUAC_RDP_ARGV_DOMAIN) == 0) { - free(settings->domain); - settings->domain = strdup(value); + guac_mem_free(settings->domain); + settings->domain = guac_strdup(value); } return 0; -} \ No newline at end of file +} diff --git a/src/protocols/rdp/beep.c b/src/protocols/rdp/beep.c index 8fb5001f..7f59dbbe 100644 --- a/src/protocols/rdp/beep.c +++ b/src/protocols/rdp/beep.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -93,14 +94,14 @@ static void guac_rdp_beep_fill_triangle_wave(unsigned char* buffer, static void guac_rdp_beep_write_pcm(guac_audio_stream* audio, int frequency, int duration) { - int buffer_size = audio->rate * duration / 1000; - unsigned char* buffer = malloc(buffer_size); + size_t buffer_size = guac_mem_ckd_mul_or_die(audio->rate, duration) / 1000; + unsigned char* buffer = guac_mem_alloc(buffer_size); /* Beep for given frequency/duration using a simple triangle wave */ guac_rdp_beep_fill_triangle_wave(buffer, frequency, audio->rate, buffer_size); guac_audio_stream_write_pcm(audio, buffer, buffer_size); - free(buffer); + guac_mem_free(buffer); } diff --git a/src/protocols/rdp/channels/audio-input/audio-buffer.c b/src/protocols/rdp/channels/audio-input/audio-buffer.c index c584b19e..38d5b7f1 100644 --- a/src/protocols/rdp/channels/audio-input/audio-buffer.c +++ b/src/protocols/rdp/channels/audio-input/audio-buffer.c @@ -21,6 +21,7 @@ #include "rdp.h" #include +#include #include #include #include @@ -116,8 +117,8 @@ static int guac_rdp_audio_buffer_duration(const guac_rdp_audio_format* format, i * The number of bytes required to store audio data in the given format * covering the given length of time. */ -static int guac_rdp_audio_buffer_length(const guac_rdp_audio_format* format, int duration) { - return duration * format->rate * format->bps * format->channels / 1000; +static size_t guac_rdp_audio_buffer_length(const guac_rdp_audio_format* format, int duration) { + return guac_mem_ckd_mul_or_die(duration, format->rate, format->bps, format->channels) / 1000; } /** @@ -261,7 +262,7 @@ static void* guac_rdp_audio_buffer_flush_thread(void* data) { guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc(guac_client* client) { - guac_rdp_audio_buffer* buffer = calloc(1, sizeof(guac_rdp_audio_buffer)); + guac_rdp_audio_buffer* buffer = guac_mem_zalloc(sizeof(guac_rdp_audio_buffer)); pthread_mutex_init(&(buffer->lock), NULL); pthread_cond_init(&(buffer->modified), NULL); @@ -395,21 +396,23 @@ void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer, audio_buffer->data = data; /* Calculate size of each packet in bytes */ - audio_buffer->packet_size = packet_frames - * audio_buffer->out_format.channels - * audio_buffer->out_format.bps; + audio_buffer->packet_size = guac_mem_ckd_mul_or_die(packet_frames, + audio_buffer->out_format.channels, + audio_buffer->out_format.bps); /* Ensure outbound buffer includes enough space for at least 250ms of * audio */ - int ideal_size = guac_rdp_audio_buffer_length(&audio_buffer->out_format, + size_t ideal_size = guac_rdp_audio_buffer_length(&audio_buffer->out_format, GUAC_RDP_AUDIO_BUFFER_MIN_DURATION); /* Round up to nearest whole packet */ - int ideal_packets = (ideal_size + audio_buffer->packet_size - 1) / audio_buffer->packet_size; + size_t ideal_packets = guac_mem_ckd_sub_or_die( + guac_mem_ckd_add_or_die(ideal_size, audio_buffer->packet_size), 1 + ) / audio_buffer->packet_size; /* Allocate new buffer */ - audio_buffer->packet_buffer_size = ideal_packets * audio_buffer->packet_size; - audio_buffer->packet = malloc(audio_buffer->packet_buffer_size); + audio_buffer->packet_buffer_size = guac_mem_ckd_mul_or_die(ideal_packets, audio_buffer->packet_size); + audio_buffer->packet = guac_mem_alloc(audio_buffer->packet_buffer_size); guac_client_log(audio_buffer->client, GUAC_LOG_DEBUG, "Output buffer for " "audio input is %i bytes (up to %i ms).", audio_buffer->packet_buffer_size, @@ -609,8 +612,7 @@ void guac_rdp_audio_buffer_end(guac_rdp_audio_buffer* audio_buffer) { audio_buffer->total_bytes_received = 0; /* Free packet (if any) */ - free(audio_buffer->packet); - audio_buffer->packet = NULL; + guac_mem_free(audio_buffer->packet); pthread_cond_broadcast(&(audio_buffer->modified)); pthread_mutex_unlock(&(audio_buffer->lock)); @@ -632,7 +634,7 @@ void guac_rdp_audio_buffer_free(guac_rdp_audio_buffer* audio_buffer) { pthread_mutex_destroy(&(audio_buffer->lock)); pthread_cond_destroy(&(audio_buffer->modified)); - free(audio_buffer); + guac_mem_free(audio_buffer); } diff --git a/src/protocols/rdp/channels/audio-input/audio-buffer.h b/src/protocols/rdp/channels/audio-input/audio-buffer.h index 723ca6a6..12719807 100644 --- a/src/protocols/rdp/channels/audio-input/audio-buffer.h +++ b/src/protocols/rdp/channels/audio-input/audio-buffer.h @@ -132,12 +132,12 @@ struct guac_rdp_audio_buffer { * The size that each audio packet must be, in bytes. The packet buffer * within this structure will be at least this size. */ - int packet_size; + size_t packet_size; /** * The total number of bytes available within the packet buffer. */ - int packet_buffer_size; + size_t packet_buffer_size; /** * The number of bytes currently stored within the packet buffer. diff --git a/src/protocols/rdp/channels/cliprdr.c b/src/protocols/rdp/channels/cliprdr.c index 4845577e..97e3ed53 100644 --- a/src/protocols/rdp/channels/cliprdr.c +++ b/src/protocols/rdp/channels/cliprdr.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -358,7 +359,7 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, guac_iconv_write* remote_writer; const char* input = clipboard->clipboard->buffer; - char* output = malloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH); + char* output = guac_mem_alloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH); /* Map requested clipboard format to a guac_iconv writer */ switch (format_data_request->requestedFormatId) { @@ -379,7 +380,7 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, "server has requested a clipboard format which was not " "declared as available. This violates the specification " "for the CLIPRDR channel."); - free(output); + guac_mem_free(output); return CHANNEL_RC_OK; } @@ -403,7 +404,7 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, UINT result = cliprdr->ClientFormatDataResponse(cliprdr, &data_response); pthread_mutex_unlock(&(rdp_client->message_lock)); - free(start); + guac_mem_free(start); return result; } @@ -593,7 +594,7 @@ static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context, guac_rdp_clipboard* guac_rdp_clipboard_alloc(guac_client* client) { /* Allocate clipboard and underlying storage */ - guac_rdp_clipboard* clipboard = calloc(1, sizeof(guac_rdp_clipboard)); + guac_rdp_clipboard* clipboard = guac_mem_zalloc(sizeof(guac_rdp_clipboard)); clipboard->client = client; clipboard->clipboard = guac_common_clipboard_alloc(); clipboard->requested_format = CF_TEXT; @@ -637,7 +638,7 @@ void guac_rdp_clipboard_free(guac_rdp_clipboard* clipboard) { /* Free clipboard and underlying storage */ guac_common_clipboard_free(clipboard->clipboard); - free(clipboard); + guac_mem_free(clipboard); } diff --git a/src/protocols/rdp/channels/common-svc.c b/src/protocols/rdp/channels/common-svc.c index ce3bf8f2..774316f4 100644 --- a/src/protocols/rdp/channels/common-svc.c +++ b/src/protocols/rdp/channels/common-svc.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,7 @@ int guac_rdp_common_svc_load_plugin(rdpContext* context, guac_client* client = ((rdp_freerdp_context*) context)->client; - guac_rdp_common_svc* svc = calloc(1, sizeof(guac_rdp_common_svc)); + guac_rdp_common_svc* svc = guac_mem_zalloc(sizeof(guac_rdp_common_svc)); svc->client = client; svc->name = svc->_channel_def.name; svc->_connect_handler = connect_handler; @@ -65,7 +66,7 @@ int guac_rdp_common_svc_load_plugin(rdpContext* context, guac_client_log(client, GUAC_LOG_WARNING, "Cannot create static " "channel \"%s\": failed to load \"guac-common-svc\" plugin " "for FreeRDP.", svc->name); - free(svc); + guac_mem_free(svc); } /* Store and log on success (SVC structure will be freed on channel termination) */ diff --git a/src/protocols/rdp/channels/disp.c b/src/protocols/rdp/channels/disp.c index 70342ebd..a8be66e0 100644 --- a/src/protocols/rdp/channels/disp.c +++ b/src/protocols/rdp/channels/disp.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,7 @@ guac_rdp_disp* guac_rdp_disp_alloc(guac_client* client) { - guac_rdp_disp* disp = malloc(sizeof(guac_rdp_disp)); + guac_rdp_disp* disp = guac_mem_alloc(sizeof(guac_rdp_disp)); disp->client = client; /* Not yet connected */ @@ -51,7 +52,7 @@ guac_rdp_disp* guac_rdp_disp_alloc(guac_client* client) { } void guac_rdp_disp_free(guac_rdp_disp* disp) { - free(disp); + guac_mem_free(disp); } /** diff --git a/src/protocols/rdp/channels/pipe-svc.c b/src/protocols/rdp/channels/pipe-svc.c index 26115508..9029c207 100644 --- a/src/protocols/rdp/channels/pipe-svc.c +++ b/src/protocols/rdp/channels/pipe-svc.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -172,7 +173,7 @@ int guac_rdp_pipe_svc_blob_handler(guac_user* user, guac_stream* stream, void guac_rdp_pipe_svc_process_connect(guac_rdp_common_svc* svc) { /* Associate SVC with new Guacamole pipe */ - guac_rdp_pipe_svc* pipe_svc = malloc(sizeof(guac_rdp_pipe_svc)); + guac_rdp_pipe_svc* pipe_svc = guac_mem_alloc(sizeof(guac_rdp_pipe_svc)); pipe_svc->svc = svc; pipe_svc->output_pipe = guac_client_alloc_stream(svc->client); svc->data = pipe_svc; @@ -214,7 +215,7 @@ void guac_rdp_pipe_svc_process_terminate(guac_rdp_common_svc* svc) { /* Remove and free SVC */ guac_rdp_pipe_svc_remove(svc->client, svc->name); - free(pipe_svc); + guac_mem_free(pipe_svc); } diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c index b2d8c415..e7caecd5 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -165,7 +166,7 @@ void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc, length = GUAC_RDP_MAX_READ_BUFFER; /* Allocate buffer */ - buffer = malloc(length); + buffer = guac_mem_alloc(length); /* Attempt read */ bytes_read = guac_rdp_fs_read((guac_rdp_fs*) device->data, @@ -187,7 +188,7 @@ void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc, } guac_rdp_common_svc_write(svc, output_stream); - free(buffer); + guac_mem_free(buffer); } diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr.c b/src/protocols/rdp/channels/rdpdr/rdpdr.c index 68bb73e4..a64a9084 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -145,7 +146,7 @@ void guac_rdpdr_process_connect(guac_rdp_common_svc* svc) { guac_client* client = svc->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; - guac_rdpdr* rdpdr = (guac_rdpdr*) calloc(1, sizeof(guac_rdpdr)); + guac_rdpdr* rdpdr = (guac_rdpdr*) guac_mem_zalloc(sizeof(guac_rdpdr)); svc->data = rdpdr; /* Register printer if enabled */ @@ -173,7 +174,7 @@ void guac_rdpdr_process_terminate(guac_rdp_common_svc* svc) { device->free_handler(svc, device); } - free(rdpdr); + guac_mem_free(svc->data); /* rdpdr */ } diff --git a/src/protocols/rdp/channels/rdpei.c b/src/protocols/rdp/channels/rdpei.c index 06d2ba4c..74b705de 100644 --- a/src/protocols/rdp/channels/rdpei.c +++ b/src/protocols/rdp/channels/rdpei.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,7 @@ guac_rdp_rdpei* guac_rdp_rdpei_alloc(guac_client* client) { - guac_rdp_rdpei* rdpei = malloc(sizeof(guac_rdp_rdpei)); + guac_rdp_rdpei* rdpei = guac_mem_alloc(sizeof(guac_rdp_rdpei)); rdpei->client = client; /* Not yet connected */ @@ -49,7 +50,7 @@ guac_rdp_rdpei* guac_rdp_rdpei_alloc(guac_client* client) { } void guac_rdp_rdpei_free(guac_rdp_rdpei* rdpei) { - free(rdpei); + guac_mem_free(rdpei); } /** diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c index 40b53150..bbbe6b5e 100644 --- a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c +++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -86,14 +87,13 @@ void guac_rdpsnd_process_receive(guac_rdp_common_svc* svc, void guac_rdpsnd_process_connect(guac_rdp_common_svc* svc) { - guac_rdpsnd* rdpsnd = (guac_rdpsnd*) calloc(1, sizeof(guac_rdpsnd)); + guac_rdpsnd* rdpsnd = (guac_rdpsnd*) guac_mem_zalloc(sizeof(guac_rdpsnd)); svc->data = rdpsnd; } void guac_rdpsnd_process_terminate(guac_rdp_common_svc* svc) { - guac_rdpsnd* rdpsnd = (guac_rdpsnd*) svc->data; - free(rdpsnd); + guac_mem_free(svc->data); } void guac_rdpsnd_load_plugin(rdpContext* context) { diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index 6054ccbb..8f8c4f68 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -194,7 +195,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) { client->args = GUAC_RDP_CLIENT_ARGS; /* Alloc client data */ - guac_rdp_client* rdp_client = calloc(1, sizeof(guac_rdp_client)); + guac_rdp_client* rdp_client = guac_mem_zalloc(sizeof(guac_rdp_client)); client->data = rdp_client; /* Init clipboard */ @@ -296,7 +297,7 @@ int guac_rdp_client_free_handler(guac_client* client) { pthread_mutex_destroy(&(rdp_client->message_lock)); /* Free client data */ - free(rdp_client); + guac_mem_free(rdp_client); return 0; diff --git a/src/protocols/rdp/download.c b/src/protocols/rdp/download.c index 582a0c27..1b6eeb76 100644 --- a/src/protocols/rdp/download.c +++ b/src/protocols/rdp/download.c @@ -24,6 +24,7 @@ #include "rdp.h" #include +#include #include #include #include @@ -72,7 +73,7 @@ int guac_rdp_download_ack_handler(guac_user* user, guac_stream* stream, else if (bytes_read == 0) { guac_protocol_send_end(user->socket, stream); guac_user_free_stream(user, stream); - free(download_status); + guac_mem_free(download_status); } /* Otherwise, fail stream */ @@ -81,7 +82,7 @@ int guac_rdp_download_ack_handler(guac_user* user, guac_stream* stream, "Error reading file for download"); guac_protocol_send_end(user->socket, stream); guac_user_free_stream(user, stream); - free(download_status); + guac_mem_free(download_status); } guac_socket_flush(user->socket); @@ -128,7 +129,7 @@ int guac_rdp_download_get_handler(guac_user* user, guac_object* object, if (file->attributes & FILE_ATTRIBUTE_DIRECTORY) { /* Create stream data */ - guac_rdp_ls_status* ls_status = malloc(sizeof(guac_rdp_ls_status)); + guac_rdp_ls_status* ls_status = guac_mem_alloc(sizeof(guac_rdp_ls_status)); ls_status->fs = fs; ls_status->file_id = file_id; guac_strlcpy(ls_status->directory_name, name, @@ -153,7 +154,7 @@ int guac_rdp_download_get_handler(guac_user* user, guac_object* object, else if (!fs->disable_download) { /* Create stream data */ - guac_rdp_download_status* download_status = malloc(sizeof(guac_rdp_download_status)); + guac_rdp_download_status* download_status = guac_mem_alloc(sizeof(guac_rdp_download_status)); download_status->file_id = file_id; download_status->offset = 0; @@ -209,7 +210,7 @@ void* guac_rdp_download_to_user(guac_user* user, void* data) { /* Associate stream with transfer status */ guac_stream* stream = guac_user_alloc_stream(user); - guac_rdp_download_status* download_status = malloc(sizeof(guac_rdp_download_status)); + guac_rdp_download_status* download_status = guac_mem_alloc(sizeof(guac_rdp_download_status)); stream->data = download_status; stream->ack_handler = guac_rdp_download_ack_handler; download_status->file_id = file_id; diff --git a/src/protocols/rdp/fs.c b/src/protocols/rdp/fs.c index 36bb28d3..be228728 100644 --- a/src/protocols/rdp/fs.c +++ b/src/protocols/rdp/fs.c @@ -22,6 +22,7 @@ #include "upload.h" #include +#include #include #include #include @@ -59,10 +60,10 @@ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path, } } - guac_rdp_fs* fs = malloc(sizeof(guac_rdp_fs)); + guac_rdp_fs* fs = guac_mem_alloc(sizeof(guac_rdp_fs)); fs->client = client; - fs->drive_path = strdup(drive_path); + fs->drive_path = guac_strdup(drive_path); fs->file_id_pool = guac_pool_alloc(0); fs->open_files = 0; fs->disable_download = disable_download; @@ -74,8 +75,8 @@ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path, void guac_rdp_fs_free(guac_rdp_fs* fs) { guac_pool_free(fs->file_id_pool); - free(fs->drive_path); - free(fs); + guac_mem_free(fs->drive_path); + guac_mem_free(fs); } guac_object* guac_rdp_fs_alloc_object(guac_rdp_fs* fs, guac_user* user) { @@ -366,8 +367,8 @@ int guac_rdp_fs_open(guac_rdp_fs* fs, const char* path, file->fd = fd; file->dir = NULL; file->dir_pattern[0] = '\0'; - file->absolute_path = strdup(normalized_path); - file->real_path = strdup(real_path); + file->absolute_path = guac_strdup(normalized_path); + file->real_path = guac_strdup(real_path); file->bytes_written = 0; guac_client_log(fs->client, GUAC_LOG_DEBUG, @@ -574,8 +575,8 @@ void guac_rdp_fs_close(guac_rdp_fs* fs, int file_id) { close(file->fd); /* Free name */ - free(file->absolute_path); - free(file->real_path); + guac_mem_free(file->absolute_path); + guac_mem_free(file->real_path); /* Free ID back to pool */ guac_pool_free_int(fs->file_id_pool, file_id); diff --git a/src/protocols/rdp/glyph.c b/src/protocols/rdp/glyph.c index d8413841..7241a385 100644 --- a/src/protocols/rdp/glyph.c +++ b/src/protocols/rdp/glyph.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -48,7 +49,7 @@ BOOL guac_rdp_glyph_new(rdpContext* context, const rdpGlyph* glyph) { /* Init Cairo buffer */ stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); - image_buffer = malloc(height*stride); + image_buffer = guac_mem_alloc(height, stride); image_buffer_row = image_buffer; /* Copy image data from image data to buffer */ @@ -118,7 +119,7 @@ void guac_rdp_glyph_free(rdpContext* context, rdpGlyph* glyph) { /* Free surface */ cairo_surface_destroy(((guac_rdp_glyph*) glyph)->surface); - free(image_buffer); + guac_mem_free(image_buffer); /* NOTE: FreeRDP-allocated memory for the rdpGlyph will NOT be * automatically released after this free handler is invoked, thus we must diff --git a/src/protocols/rdp/keyboard.c b/src/protocols/rdp/keyboard.c index c263a564..bb014b0d 100644 --- a/src/protocols/rdp/keyboard.c +++ b/src/protocols/rdp/keyboard.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -440,7 +441,7 @@ static void guac_rdp_keyboard_load_keymap(guac_rdp_keyboard* keyboard, guac_rdp_keyboard* guac_rdp_keyboard_alloc(guac_client* client, const guac_rdp_keymap* keymap) { - guac_rdp_keyboard* keyboard = calloc(1, sizeof(guac_rdp_keyboard)); + guac_rdp_keyboard* keyboard = guac_mem_zalloc(sizeof(guac_rdp_keyboard)); keyboard->client = client; /* Load keymap into keyboard */ @@ -451,7 +452,7 @@ guac_rdp_keyboard* guac_rdp_keyboard_alloc(guac_client* client, } void guac_rdp_keyboard_free(guac_rdp_keyboard* keyboard) { - free(keyboard); + guac_mem_free(keyboard); } int guac_rdp_keyboard_is_defined(guac_rdp_keyboard* keyboard, int keysym) { diff --git a/src/protocols/rdp/ls.c b/src/protocols/rdp/ls.c index f0a3b8f4..f284df3f 100644 --- a/src/protocols/rdp/ls.c +++ b/src/protocols/rdp/ls.c @@ -21,6 +21,7 @@ #include "ls.h" #include +#include #include #include #include @@ -44,7 +45,7 @@ int guac_rdp_ls_ack_handler(guac_user* user, guac_stream* stream, if (status != GUAC_PROTOCOL_STATUS_SUCCESS) { guac_rdp_fs_close(ls_status->fs, ls_status->file_id); guac_user_free_stream(user, stream); - free(ls_status); + guac_mem_free(ls_status); return 0; } @@ -108,7 +109,7 @@ int guac_rdp_ls_ack_handler(guac_user* user, guac_stream* stream, /* Clean up resources */ guac_rdp_fs_close(ls_status->fs, ls_status->file_id); - free(ls_status); + guac_mem_free(ls_status); /* Signal of stream */ guac_protocol_send_end(user->socket, stream); diff --git a/src/protocols/rdp/plugins/channels.c b/src/protocols/rdp/plugins/channels.c index 0048b891..342ca33b 100644 --- a/src/protocols/rdp/plugins/channels.c +++ b/src/protocols/rdp/plugins/channels.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -126,7 +127,7 @@ void guac_freerdp_dynamic_channel_collection_add(rdpSettings* settings, va_start(args, name); /* Copy argument values into DVC entry */ - freerdp_args->argv = malloc(sizeof(char*) * freerdp_args->argc); + freerdp_args->argv = malloc(guac_mem_ckd_mul_or_die(sizeof(char*), freerdp_args->argc)); freerdp_args->argv[0] = strdup(name); int i; for (i = 1; i < freerdp_args->argc; i++) diff --git a/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c b/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c index 027e7732..889e4ed4 100644 --- a/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c +++ b/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -203,7 +204,7 @@ static void guac_rdp_common_svc_process_terminate(guac_rdp_common_svc* svc) { guac_client_log(svc->client, GUAC_LOG_DEBUG, "SVC \"%s\" disconnected.", svc->name); - free(svc); + guac_mem_free(svc); } diff --git a/src/protocols/rdp/plugins/guacai/guacai.c b/src/protocols/rdp/plugins/guacai/guacai.c index 0d453505..36da5455 100644 --- a/src/protocols/rdp/plugins/guacai/guacai.c +++ b/src/protocols/rdp/plugins/guacai/guacai.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -149,7 +150,7 @@ static UINT guac_rdp_ai_close(IWTSVirtualChannelCallback* channel_callback) { "AUDIO_INPUT channel connection closed"); guac_rdp_audio_buffer_end(audio_buffer); - free(ai_channel_callback); + guac_mem_free(ai_channel_callback); return CHANNEL_RC_OK; } @@ -199,7 +200,7 @@ static UINT guac_rdp_ai_new_connection( /* Allocate new channel callback */ guac_rdp_ai_channel_callback* ai_channel_callback = - calloc(1, sizeof(guac_rdp_ai_channel_callback)); + guac_mem_zalloc(sizeof(guac_rdp_ai_channel_callback)); /* Init listener callback with data from plugin */ ai_channel_callback->client = ai_listener_callback->client; @@ -233,7 +234,7 @@ static UINT guac_rdp_ai_initialize(IWTSPlugin* plugin, /* Allocate new listener callback */ guac_rdp_ai_listener_callback* ai_listener_callback = - calloc(1, sizeof(guac_rdp_ai_listener_callback)); + guac_mem_zalloc(sizeof(guac_rdp_ai_listener_callback)); /* Ensure listener callback is freed when plugin is terminated */ guac_rdp_ai_plugin* ai_plugin = (guac_rdp_ai_plugin*) plugin; @@ -268,8 +269,8 @@ static UINT guac_rdp_ai_terminated(IWTSPlugin* plugin) { guac_client* client = ai_plugin->client; /* Free all non-FreeRDP data */ - free(ai_plugin->listener_callback); - free(ai_plugin); + guac_mem_free(ai_plugin->listener_callback); + guac_mem_free(ai_plugin); guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT plugin unloaded."); return CHANNEL_RC_OK; @@ -293,7 +294,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { if (ai_plugin == NULL) { /* Init plugin callbacks and data */ - ai_plugin = calloc(1, sizeof(guac_rdp_ai_plugin)); + ai_plugin = guac_mem_zalloc(sizeof(guac_rdp_ai_plugin)); ai_plugin->parent.Initialize = guac_rdp_ai_initialize; ai_plugin->parent.Terminated = guac_rdp_ai_terminated; ai_plugin->client = client; diff --git a/src/protocols/rdp/print-job.c b/src/protocols/rdp/print-job.c index 49efbfdc..2b6ca1aa 100644 --- a/src/protocols/rdp/print-job.c +++ b/src/protocols/rdp/print-job.c @@ -21,6 +21,7 @@ #include "rdp.h" #include +#include #include #include #include @@ -454,7 +455,7 @@ void* guac_rdp_print_job_alloc(guac_user* user, void* data) { return NULL; /* Bail early if allocation fails */ - guac_rdp_print_job* job = malloc(sizeof(guac_rdp_print_job)); + guac_rdp_print_job* job = guac_mem_alloc(sizeof(guac_rdp_print_job)); if (job == NULL) return NULL; @@ -478,7 +479,7 @@ void* guac_rdp_print_job_alloc(guac_user* user, void* data) { /* Abort if print filter process cannot be created */ if (job->filter_pid == -1) { guac_user_free_stream(user, stream); - free(job); + guac_mem_free(job); return NULL; } @@ -659,7 +660,7 @@ void guac_rdp_print_job_free(guac_rdp_print_job* job) { pthread_mutex_destroy(&(job->state_lock)); /* Free base structure */ - free(job); + guac_mem_free(job); } diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index 7b90f683..f9e7e17d 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -288,9 +289,9 @@ static BOOL rdp_freerdp_authenticate(freerdp* instance, char** username, guac_argv_await((const char**) params); /* Free old values and get new values from settings. */ - free(*username); - free(*password); - free(*domain); + guac_mem_free(*username); + guac_mem_free(*password); + guac_mem_free(*domain); *username = guac_strdup(settings->username); *password = guac_strdup(settings->password); *domain = guac_strdup(settings->domain); diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index c286c71b..b259fc9d 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -683,7 +684,7 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, return NULL; } - guac_rdp_settings* settings = calloc(1, sizeof(guac_rdp_settings)); + guac_rdp_settings* settings = guac_mem_zalloc(sizeof(guac_rdp_settings)); /* Use console */ settings->console = @@ -962,7 +963,7 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, /* Preconnection BLOB */ settings->preconnection_blob = NULL; if (argv[IDX_PRECONNECTION_BLOB][0] != '\0') { - settings->preconnection_blob = strdup(argv[IDX_PRECONNECTION_BLOB]); + settings->preconnection_blob = guac_strdup(argv[IDX_PRECONNECTION_BLOB]); guac_user_log(user, GUAC_LOG_DEBUG, "Preconnection BLOB: \"%s\"", settings->preconnection_blob); } @@ -1278,22 +1279,22 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, void guac_rdp_settings_free(guac_rdp_settings* settings) { /* Free settings strings */ - free(settings->client_name); - free(settings->domain); - free(settings->drive_name); - free(settings->drive_path); - free(settings->hostname); - free(settings->initial_program); - free(settings->password); - free(settings->preconnection_blob); - free(settings->recording_name); - free(settings->recording_path); - free(settings->remote_app); - free(settings->remote_app_args); - free(settings->remote_app_dir); - free(settings->timezone); - free(settings->username); - free(settings->printer_name); + guac_mem_free(settings->client_name); + guac_mem_free(settings->domain); + guac_mem_free(settings->drive_name); + guac_mem_free(settings->drive_path); + guac_mem_free(settings->hostname); + guac_mem_free(settings->initial_program); + guac_mem_free(settings->password); + guac_mem_free(settings->preconnection_blob); + guac_mem_free(settings->recording_name); + guac_mem_free(settings->recording_path); + guac_mem_free(settings->remote_app); + guac_mem_free(settings->remote_app_args); + guac_mem_free(settings->remote_app_dir); + guac_mem_free(settings->timezone); + guac_mem_free(settings->username); + guac_mem_free(settings->printer_name); /* Free channel name array */ if (settings->svc_names != NULL) { @@ -1301,43 +1302,43 @@ void guac_rdp_settings_free(guac_rdp_settings* settings) { /* Free all elements of array */ char** current = &(settings->svc_names[0]); while (*current != NULL) { - free(*current); + guac_mem_free(*current); current++; } /* Free array itself */ - free(settings->svc_names); + guac_mem_free(settings->svc_names); } #ifdef ENABLE_COMMON_SSH /* Free SFTP settings */ - free(settings->sftp_directory); - free(settings->sftp_root_directory); - free(settings->sftp_host_key); - free(settings->sftp_hostname); - free(settings->sftp_passphrase); - free(settings->sftp_password); - free(settings->sftp_port); - free(settings->sftp_private_key); - free(settings->sftp_username); + guac_mem_free(settings->sftp_directory); + guac_mem_free(settings->sftp_root_directory); + guac_mem_free(settings->sftp_host_key); + guac_mem_free(settings->sftp_hostname); + guac_mem_free(settings->sftp_passphrase); + guac_mem_free(settings->sftp_password); + guac_mem_free(settings->sftp_port); + guac_mem_free(settings->sftp_private_key); + guac_mem_free(settings->sftp_username); #endif /* Free RD gateway information */ - free(settings->gateway_hostname); - free(settings->gateway_domain); - free(settings->gateway_username); - free(settings->gateway_password); + guac_mem_free(settings->gateway_hostname); + guac_mem_free(settings->gateway_domain); + guac_mem_free(settings->gateway_username); + guac_mem_free(settings->gateway_password); /* Free load balancer information string */ - free(settings->load_balance_info); + guac_mem_free(settings->load_balance_info); /* Free Wake-on-LAN strings */ - free(settings->wol_mac_addr); - free(settings->wol_broadcast_addr); + guac_mem_free(settings->wol_mac_addr); + guac_mem_free(settings->wol_broadcast_addr); /* Free settings structure */ - free(settings); + guac_mem_free(settings); } diff --git a/src/protocols/rdp/tests/fs/normalize_path.c b/src/protocols/rdp/tests/fs/normalize_path.c index 22a2d809..8640dab8 100644 --- a/src/protocols/rdp/tests/fs/normalize_path.c +++ b/src/protocols/rdp/tests/fs/normalize_path.c @@ -19,6 +19,8 @@ #include "fs.h" +#include + #include #include @@ -160,7 +162,7 @@ void test_fs__normalize_relative_mixed() { * Generates a dynamically-allocated path having the given number of bytes, not * counting the null-terminator. The path will contain only Windows-style path * separators. The returned path must eventually be freed with a call to - * free(). + * guac_mem_free(). * * @param length * The number of bytes to include in the generated path, not counting the @@ -174,7 +176,7 @@ void test_fs__normalize_relative_mixed() { * @return * A dynamically-allocated path containing the given number of bytes, not * counting the null-terminator. This path must eventually be freed with a - * call to free(). + * call to guac_mem_free(). */ static char* generate_path(int length, int max_depth) { @@ -183,7 +185,7 @@ static char* generate_path(int length, int max_depth) { length = max_depth * 2; int i; - char* input = malloc(length + 1); + char* input = guac_mem_alloc(guac_mem_ckd_add_or_die(length, 1)); /* Fill path with \x\x\x\x\x\x\x\x\x\x\...\xxxxxxxxx... */ for (i = 0; i < length; i++) { @@ -214,17 +216,17 @@ void test_fs__normalize_long() { /* Exceeds maximum length by a factor of 2 */ input = generate_path(GUAC_RDP_FS_MAX_PATH * 2, GUAC_RDP_MAX_PATH_DEPTH); CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); - free(input); + guac_mem_free(input); /* Exceeds maximum length by one byte */ input = generate_path(GUAC_RDP_FS_MAX_PATH, GUAC_RDP_MAX_PATH_DEPTH); CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); - free(input); + guac_mem_free(input); /* Exactly maximum length */ input = generate_path(GUAC_RDP_FS_MAX_PATH - 1, GUAC_RDP_MAX_PATH_DEPTH); CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); - free(input); + guac_mem_free(input); } @@ -240,17 +242,17 @@ void test_fs__normalize_deep() { /* Exceeds maximum depth by a factor of 2 */ input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH * 2); CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); - free(input); + guac_mem_free(input); /* Exceeds maximum depth by one component */ input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH + 1); CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); - free(input); + guac_mem_free(input); /* Exactly maximum depth */ input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH); CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); - free(input); + guac_mem_free(input); } diff --git a/src/protocols/rdp/upload.c b/src/protocols/rdp/upload.c index 2b08b2f7..ecc49718 100644 --- a/src/protocols/rdp/upload.c +++ b/src/protocols/rdp/upload.c @@ -22,6 +22,7 @@ #include "upload.h" #include +#include #include #include #include @@ -113,7 +114,7 @@ int guac_rdp_upload_file_handler(guac_user* user, guac_stream* stream, } /* Init upload status */ - guac_rdp_upload_status* upload_status = malloc(sizeof(guac_rdp_upload_status)); + guac_rdp_upload_status* upload_status = guac_mem_alloc(sizeof(guac_rdp_upload_status)); upload_status->offset = 0; upload_status->file_id = file_id; stream->data = upload_status; @@ -197,7 +198,7 @@ int guac_rdp_upload_end_handler(guac_user* user, guac_stream* stream) { GUAC_PROTOCOL_STATUS_SUCCESS); guac_socket_flush(user->socket); - free(upload_status); + guac_mem_free(upload_status); return 0; } @@ -242,7 +243,7 @@ int guac_rdp_upload_put_handler(guac_user* user, guac_object* object, } /* Init upload stream data */ - guac_rdp_upload_status* upload_status = malloc(sizeof(guac_rdp_upload_status)); + guac_rdp_upload_status* upload_status = guac_mem_alloc(sizeof(guac_rdp_upload_status)); upload_status->offset = 0; upload_status->file_id = file_id; From 0c538b057472b7f53676575f9f5c6a7869e35efb Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Sun, 15 Oct 2023 21:11:35 -0700 Subject: [PATCH 08/15] GUACAMOLE-1867: Migrate terminal emulator to new memory management functions. --- src/terminal/buffer.c | 20 +++++++++++--------- src/terminal/display.c | 15 ++++++++------- src/terminal/scrollbar.c | 5 +++-- src/terminal/terminal.c | 30 ++++++++++++++++-------------- src/terminal/terminal/terminal.h | 2 +- src/terminal/typescript.c | 11 ++++++----- 6 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/terminal/buffer.c b/src/terminal/buffer.c index e8ad4b3c..1d1d7293 100644 --- a/src/terminal/buffer.c +++ b/src/terminal/buffer.c @@ -21,6 +21,8 @@ #include "terminal/buffer.h" #include "terminal/common.h" +#include + #include #include @@ -28,7 +30,7 @@ guac_terminal_buffer* guac_terminal_buffer_alloc(int rows, guac_terminal_char* d /* Allocate scrollback */ guac_terminal_buffer* buffer = - malloc(sizeof(guac_terminal_buffer)); + guac_mem_alloc(sizeof(guac_terminal_buffer)); int i; guac_terminal_buffer_row* row; @@ -38,8 +40,7 @@ guac_terminal_buffer* guac_terminal_buffer_alloc(int rows, guac_terminal_char* d buffer->available = rows; buffer->top = 0; buffer->length = 0; - buffer->rows = malloc(sizeof(guac_terminal_buffer_row) * - buffer->available); + buffer->rows = guac_mem_alloc(sizeof(guac_terminal_buffer_row), buffer->available); /* Init scrollback rows */ row = buffer->rows; @@ -48,7 +49,7 @@ guac_terminal_buffer* guac_terminal_buffer_alloc(int rows, guac_terminal_char* d /* Allocate row */ row->available = 256; row->length = 0; - row->characters = malloc(sizeof(guac_terminal_char) * row->available); + row->characters = guac_mem_alloc(sizeof(guac_terminal_char), row->available); /* Next row */ row++; @@ -66,13 +67,13 @@ void guac_terminal_buffer_free(guac_terminal_buffer* buffer) { /* Free all rows */ for (i=0; iavailable; i++) { - free(row->characters); + guac_mem_free(row->characters); row++; } /* Free actual buffer */ - free(buffer->rows); - free(buffer); + guac_mem_free(buffer->rows); + guac_mem_free(buffer); } @@ -95,8 +96,9 @@ guac_terminal_buffer_row* guac_terminal_buffer_get_row(guac_terminal_buffer* buf /* Expand if necessary */ if (width > buffer_row->available) { - buffer_row->available = width*2; - buffer_row->characters = realloc(buffer_row->characters, sizeof(guac_terminal_char) * buffer_row->available); + buffer_row->available = guac_mem_ckd_mul_or_die(width, 2); + buffer_row->characters = guac_mem_realloc(buffer_row->characters, + sizeof(guac_terminal_char), buffer_row->available); } /* Initialize new part of row */ diff --git a/src/terminal/display.c b/src/terminal/display.c index 92d86677..b053bf78 100644 --- a/src/terminal/display.c +++ b/src/terminal/display.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -208,7 +209,7 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client, guac_terminal_color (*palette)[256]) { /* Allocate display */ - guac_terminal_display* display = malloc(sizeof(guac_terminal_display)); + guac_terminal_display* display = guac_mem_alloc(sizeof(guac_terminal_display)); display->client = client; /* Initially no font loaded */ @@ -245,7 +246,7 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client, if (guac_terminal_display_set_font(display, font_name, font_size, dpi)) { guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to set initial font \"%s\"", font_name); - free(display); + guac_mem_free(display); return NULL; } @@ -259,13 +260,13 @@ void guac_terminal_display_free(guac_terminal_display* display) { pango_font_description_free(display->font_desc); /* Free default palette. */ - free(display->default_palette); + guac_mem_free(display->default_palette); /* Free operations buffers */ - free(display->operations); + guac_mem_free(display->operations); /* Free display */ - free(display); + guac_mem_free(display); } @@ -462,10 +463,10 @@ void guac_terminal_display_resize(guac_terminal_display* display, int width, int /* Free old operations buffer */ if (display->operations != NULL) - free(display->operations); + guac_mem_free(display->operations); /* Alloc operations */ - display->operations = malloc(width * height * + display->operations = guac_mem_alloc(width, height, sizeof(guac_terminal_operation)); /* Init each operation buffer row */ diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index 6b5ac7ab..9a89474b 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -32,7 +33,7 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, /* Allocate scrollbar */ guac_terminal_scrollbar* scrollbar = - malloc(sizeof(guac_terminal_scrollbar)); + guac_mem_alloc(sizeof(guac_terminal_scrollbar)); /* Associate client */ scrollbar->client = client; @@ -82,7 +83,7 @@ void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { guac_client_free_layer(scrollbar->client, scrollbar->container); /* Free scrollbar */ - free(scrollbar); + guac_mem_free(scrollbar); } diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index ad539eaf..77141aa7 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -45,8 +45,10 @@ #include #include +#include #include #include +#include #include /** @@ -317,7 +319,7 @@ void* guac_terminal_thread(void* data) { guac_terminal_options* guac_terminal_options_create( int width, int height, int dpi) { - guac_terminal_options* options = malloc(sizeof(guac_terminal_options)); + guac_terminal_options* options = guac_mem_alloc(sizeof(guac_terminal_options)); /* Set all required parameters */ options->width = width; @@ -356,7 +358,7 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Initialized by guac_terminal_parse_color_scheme. */ guac_terminal_color (*default_palette)[256] = (guac_terminal_color(*)[256]) - malloc(sizeof(guac_terminal_color[256])); + guac_mem_alloc(sizeof(guac_terminal_color[256])); guac_terminal_parse_color_scheme(client, options->color_scheme, &default_char.attributes.foreground, @@ -368,15 +370,15 @@ guac_terminal* guac_terminal_create(guac_client* client, if (available_width < 0) available_width = 0; - guac_terminal* term = malloc(sizeof(guac_terminal)); + guac_terminal* term = guac_mem_alloc(sizeof(guac_terminal)); term->started = false; term->client = client; term->upload_path_handler = NULL; term->file_download_handler = NULL; /* Copy initially-provided color scheme and font details */ - term->color_scheme = strdup(options->color_scheme); - term->font_name = strdup(options->font_name); + term->color_scheme = guac_strdup(options->color_scheme); + term->font_name = guac_strdup(options->font_name); term->font_size = options->font_size; /* Set size of available screen area */ @@ -412,7 +414,7 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Fail if display init failed */ if (term->display == NULL) { guac_client_log(client, GUAC_LOG_DEBUG, "Display initialization failed"); - free(term); + guac_mem_free(term); return NULL; } @@ -453,7 +455,7 @@ guac_terminal* guac_terminal_create(guac_client* client, if (pipe(term->stdin_pipe_fd)) { guac_error = GUAC_STATUS_SEE_ERRNO; guac_error_message = "Unable to open pipe for STDIN"; - free(term); + guac_mem_free(term); return NULL; } @@ -553,14 +555,14 @@ void guac_terminal_free(guac_terminal* term) { guac_terminal_scrollbar_free(term->scrollbar); /* Free copies of font and color scheme information */ - free((char*) term->color_scheme); - free((char*) term->font_name); + guac_mem_free_const(term->color_scheme); + guac_mem_free_const(term->font_name); /* Free clipboard */ guac_common_clipboard_free(term->clipboard); /* Free the terminal itself */ - free(term); + guac_mem_free(term); } @@ -783,7 +785,7 @@ char* guac_terminal_prompt(guac_terminal* terminal, const char* title, buffer[pos] = 0; /* Return newly-allocated string containing result */ - return strdup(buffer); + return guac_strdup(buffer); } @@ -2048,8 +2050,8 @@ void guac_terminal_apply_color_scheme(guac_terminal* terminal, guac_terminal_lock(terminal); /* Update stored copy of color scheme */ - free((char*) terminal->color_scheme); - terminal->color_scheme = strdup(color_scheme); + guac_mem_free_const(terminal->color_scheme); + terminal->color_scheme = guac_strdup(color_scheme); /* Release terminal */ guac_terminal_unlock(terminal); @@ -2087,7 +2089,7 @@ void guac_terminal_apply_font(guac_terminal* terminal, const char* font_name, /* Update stored copy of font name, if changed */ if (font_name != NULL) - terminal->font_name = strdup(font_name); + terminal->font_name = guac_strdup(font_name); /* Update stored copy of font size, if changed */ if (font_size != -1) diff --git a/src/terminal/terminal/terminal.h b/src/terminal/terminal/terminal.h index 221937f8..cb3ed248 100644 --- a/src/terminal/terminal/terminal.h +++ b/src/terminal/terminal/terminal.h @@ -413,7 +413,7 @@ void guac_terminal_notify(guac_terminal* terminal); * @return * A newly-allocated string containing a single line of input read from the * provided terminal's STDIN. This string must eventually be manually - * freed with a call to free(). + * freed with a call to guac_mem_free(). */ char* guac_terminal_prompt(guac_terminal* terminal, const char* title, bool echo); diff --git a/src/terminal/typescript.c b/src/terminal/typescript.c index 180547c6..abc8486f 100644 --- a/src/terminal/typescript.c +++ b/src/terminal/typescript.c @@ -20,6 +20,7 @@ #include "common/io.h" #include "terminal/typescript.h" +#include #include #include @@ -117,7 +118,7 @@ guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path, /* Allocate space for new typescript */ guac_terminal_typescript* typescript = - malloc(sizeof(guac_terminal_typescript)); + guac_mem_alloc(sizeof(guac_terminal_typescript)); /* Attempt to open typescript data file */ typescript->data_fd = guac_terminal_typescript_open_data_file( @@ -125,7 +126,7 @@ guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path, sizeof(typescript->data_filename) - sizeof(GUAC_TERMINAL_TYPESCRIPT_TIMING_SUFFIX)); if (typescript->data_fd == -1) { - free(typescript); + guac_mem_free(typescript); return NULL; } @@ -134,7 +135,7 @@ guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path, "%s.%s", typescript->data_filename, GUAC_TERMINAL_TYPESCRIPT_TIMING_SUFFIX) >= sizeof(typescript->timing_filename)) { close(typescript->data_fd); - free(typescript); + guac_mem_free(typescript); return NULL; } @@ -144,7 +145,7 @@ guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path, S_IRUSR | S_IWUSR | S_IRGRP); if (typescript->timing_fd == -1) { close(typescript->data_fd); - free(typescript); + guac_mem_free(typescript); return NULL; } @@ -228,7 +229,7 @@ void guac_terminal_typescript_free(guac_terminal_typescript* typescript) { close(typescript->timing_fd); /* Free allocated typescript data */ - free(typescript); + guac_mem_free(typescript); } From 944718174d71298522c8dc2c4e5231bc74a04bd9 Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Sun, 15 Oct 2023 21:12:03 -0700 Subject: [PATCH 09/15] GUACAMOLE-1867: Migrate SSH to new memory management functions. --- src/common-ssh/buffer.c | 6 ++- src/common-ssh/common-ssh/ssh.h | 2 +- src/common-ssh/key.c | 14 +++---- src/common-ssh/sftp.c | 21 +++++----- src/common-ssh/ssh.c | 22 ++++++----- src/common-ssh/tests/sftp/normalize_path.c | 24 ++++++------ src/common-ssh/user.c | 17 ++++---- src/protocols/ssh/client.c | 5 ++- src/protocols/ssh/settings.c | 45 +++++++++++----------- src/protocols/ssh/ssh.c | 3 +- src/protocols/ssh/ssh_agent.c | 3 +- 11 files changed, 88 insertions(+), 74 deletions(-) diff --git a/src/common-ssh/buffer.c b/src/common-ssh/buffer.c index aa79bafa..b7763f69 100644 --- a/src/common-ssh/buffer.c +++ b/src/common-ssh/buffer.c @@ -22,6 +22,8 @@ #include #include +#include + #include #include #include @@ -67,7 +69,7 @@ void guac_common_ssh_buffer_write_bignum(char** buffer, const BIGNUM* value) { /* Allocate output buffer, add padding byte */ length = BN_num_bytes(value); - bn_buffer = malloc(length); + bn_buffer = guac_mem_alloc(length); /* Convert BIGNUM */ BN_bn2bin(value, bn_buffer); @@ -84,7 +86,7 @@ void guac_common_ssh_buffer_write_bignum(char** buffer, const BIGNUM* value) { memcpy(*buffer, bn_buffer, length); *buffer += length; - free(bn_buffer); + guac_mem_free(bn_buffer); } diff --git a/src/common-ssh/common-ssh/ssh.h b/src/common-ssh/common-ssh/ssh.h index 346d8abc..986c63b2 100644 --- a/src/common-ssh/common-ssh/ssh.h +++ b/src/common-ssh/common-ssh/ssh.h @@ -38,7 +38,7 @@ * * @return * A newly-allocated string containing the credentials provided by - * the user, which must be freed by a call to free(). + * the user, which must be freed by a call to guac_mem_free(). */ typedef char* guac_ssh_credential_handler(guac_client* client, char* cred_name); diff --git a/src/common-ssh/key.c b/src/common-ssh/key.c index cecfb413..ddc84179 100644 --- a/src/common-ssh/key.c +++ b/src/common-ssh/key.c @@ -22,6 +22,7 @@ #include "common-ssh/buffer.h" #include "common-ssh/key.h" +#include #include #include @@ -137,13 +138,13 @@ guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length, if (is_passphrase_needed(data, length) && (passphrase == NULL || *passphrase == '\0')) return NULL; - guac_common_ssh_key* key = malloc(sizeof(guac_common_ssh_key)); + guac_common_ssh_key* key = guac_mem_alloc(sizeof(guac_common_ssh_key)); /* Copy private key to structure */ key->private_key_length = length; - key->private_key = malloc(length); + key->private_key = guac_mem_alloc(length); memcpy(key->private_key, data, length); - key->passphrase = strdup(passphrase); + key->passphrase = guac_strdup(passphrase); return key; @@ -157,10 +158,9 @@ const char* guac_common_ssh_key_error() { } void guac_common_ssh_key_free(guac_common_ssh_key* key) { - - free(key->private_key); - free(key->passphrase); - free(key); + guac_mem_free(key->private_key); + guac_mem_free(key->passphrase); + guac_mem_free(key); } int guac_common_ssh_verify_host_key(LIBSSH2_SESSION* session, guac_client* client, diff --git a/src/common-ssh/sftp.c b/src/common-ssh/sftp.c index 0100cc16..4a6f7716 100644 --- a/src/common-ssh/sftp.c +++ b/src/common-ssh/sftp.c @@ -21,6 +21,7 @@ #include "common-ssh/ssh.h" #include +#include #include #include #include @@ -622,7 +623,7 @@ static int guac_common_ssh_sftp_ls_ack_handler(guac_user* user, if (status != GUAC_PROTOCOL_STATUS_SUCCESS) { libssh2_sftp_closedir(list_state->directory); guac_user_free_stream(user, stream); - free(list_state); + guac_mem_free(list_state); return 0; } @@ -674,7 +675,7 @@ static int guac_common_ssh_sftp_ls_ack_handler(guac_user* user, /* Clean up resources */ libssh2_sftp_closedir(list_state->directory); - free(list_state); + guac_mem_free(list_state); /* Signal of stream */ guac_protocol_send_end(user->socket, stream); @@ -774,7 +775,7 @@ static int guac_common_ssh_sftp_get_handler(guac_user* user, /* Init directory listing state */ guac_common_ssh_sftp_ls_state* list_state = - malloc(sizeof(guac_common_ssh_sftp_ls_state)); + guac_mem_alloc(sizeof(guac_common_ssh_sftp_ls_state)); list_state->directory = dir; list_state->filesystem = filesystem; @@ -786,7 +787,7 @@ static int guac_common_ssh_sftp_get_handler(guac_user* user, if (length >= sizeof(list_state->directory_name)) { guac_user_log(user, GUAC_LOG_INFO, "Unable to read directory " "\"%s\": Path too long", fullpath); - free(list_state); + guac_mem_free(list_state); return 0; } @@ -969,7 +970,7 @@ guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( /* Allocate data for SFTP session */ guac_common_ssh_sftp_filesystem* filesystem = - malloc(sizeof(guac_common_ssh_sftp_filesystem)); + guac_mem_alloc(sizeof(guac_common_ssh_sftp_filesystem)); /* Associate SSH session with SFTP data and user */ filesystem->ssh_session = session; @@ -984,15 +985,15 @@ guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( root_path)) { guac_client_log(session->client, GUAC_LOG_WARNING, "Cannot create " "SFTP filesystem - \"%s\" is not a valid path.", root_path); - free(filesystem); + guac_mem_free(filesystem); return NULL; } /* Generate filesystem name from root path if no name is provided */ if (name != NULL) - filesystem->name = strdup(name); + filesystem->name = guac_strdup(name); else - filesystem->name = strdup(filesystem->root_path); + filesystem->name = guac_strdup(filesystem->root_path); /* Initially upload files to current directory */ strcpy(filesystem->upload_path, "."); @@ -1009,8 +1010,8 @@ void guac_common_ssh_destroy_sftp_filesystem( libssh2_sftp_shutdown(filesystem->sftp_session); /* Free associated memory */ - free(filesystem->name); - free(filesystem); + guac_mem_free(filesystem->name); + guac_mem_free(filesystem); } diff --git a/src/common-ssh/ssh.c b/src/common-ssh/ssh.c index 373b9f12..c4c3b4cc 100644 --- a/src/common-ssh/ssh.c +++ b/src/common-ssh/ssh.c @@ -23,6 +23,8 @@ #include #include +#include +#include #include #ifdef LIBSSH2_USES_GCRYPT @@ -120,7 +122,7 @@ static void guac_common_ssh_openssl_init_locks(int count) { /* Allocate required number of locks */ guac_common_ssh_openssl_locks = - malloc(sizeof(pthread_mutex_t) * count); + guac_mem_alloc(sizeof(pthread_mutex_t), count); /* Initialize each lock */ for (i=0; i < count; i++) @@ -147,7 +149,7 @@ static void guac_common_ssh_openssl_free_locks(int count) { pthread_mutex_destroy(&(guac_common_ssh_openssl_locks[i])); /* Free lock array */ - free(guac_common_ssh_openssl_locks); + guac_mem_free(guac_common_ssh_openssl_locks); } #endif @@ -249,7 +251,7 @@ static void guac_common_ssh_kbd_callback(const char *name, int name_len, /* Send password if only one prompt */ if (num_prompts == 1) { char* password = common_session->user->password; - responses[0].text = strdup(password); + responses[0].text = guac_strdup(password); responses[0].length = strlen(password); } @@ -486,7 +488,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, /* Allocate new session */ guac_common_ssh_session* common_session = - malloc(sizeof(guac_common_ssh_session)); + guac_mem_alloc(sizeof(guac_common_ssh_session)); /* Open SSH session */ LIBSSH2_SESSION* session = libssh2_session_init_ex(NULL, NULL, @@ -494,7 +496,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, if (session == NULL) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Session allocation failed."); - free(common_session); + guac_mem_free(common_session); close(fd); return NULL; } @@ -514,7 +516,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, if (libssh2_session_handshake(session, fd)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "SSH handshake failed."); - free(common_session); + guac_mem_free(common_session); close(fd); return NULL; } @@ -527,7 +529,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, if (!remote_hostkey) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Failed to get host key for %s", hostname); - free(common_session); + guac_mem_free(common_session); close(fd); return NULL; } @@ -550,7 +552,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Host key did not match any provided known host keys. %s", err_msg); - free(common_session); + guac_mem_free(common_session); close(fd); return NULL; } @@ -564,7 +566,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, /* Attempt authentication */ if (guac_common_ssh_authenticate(common_session)) { - free(common_session); + guac_mem_free(common_session); close(fd); return NULL; } @@ -595,6 +597,6 @@ void guac_common_ssh_destroy_session(guac_common_ssh_session* session) { libssh2_session_free(session->session); /* Free all other data */ - free(session); + guac_mem_free(session); } diff --git a/src/common-ssh/tests/sftp/normalize_path.c b/src/common-ssh/tests/sftp/normalize_path.c index 151b1835..df586c10 100644 --- a/src/common-ssh/tests/sftp/normalize_path.c +++ b/src/common-ssh/tests/sftp/normalize_path.c @@ -19,6 +19,8 @@ #include "common-ssh/sftp.h" +#include + #include #include @@ -160,7 +162,7 @@ void test_sftp__normalize_relative_mixed() { * Generates a dynamically-allocated path having the given number of bytes, not * counting the null-terminator. The path will contain only UNIX-style path * separators. The returned path must eventually be freed with a call to - * free(). + * guac_mem_free(). * * @param length * The number of bytes to include in the generated path, not counting the @@ -174,16 +176,16 @@ void test_sftp__normalize_relative_mixed() { * @return * A dynamically-allocated path containing the given number of bytes, not * counting the null-terminator. This path must eventually be freed with a - * call to free(). + * call to guac_mem_free(). */ static char* generate_path(int length, int max_depth) { /* If no length given, calculate space required from max_depth */ if (length == -1) - length = max_depth * 2; + length = guac_mem_ckd_mul_or_die(max_depth, 2); int i; - char* input = malloc(length + 1); + char* input = guac_mem_alloc(guac_mem_ckd_add_or_die(length, 1)); /* Fill path with /x/x/x/x/x/x/x/x/x/x/.../xxxxxxxxx... */ for (i = 0; i < length; i++) { @@ -214,17 +216,17 @@ void test_sftp__normalize_long() { /* Exceeds maximum length by a factor of 2 */ input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH * 2, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); - free(input); + guac_mem_free(input); /* Exceeds maximum length by one byte */ input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); - free(input); + guac_mem_free(input); /* Exactly maximum length */ input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH - 1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); - free(input); + guac_mem_free(input); } @@ -240,24 +242,24 @@ void test_sftp__normalize_deep() { /* Exceeds maximum depth by a factor of 2 */ input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH * 2); CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); - free(input); + guac_mem_free(input); /* Exceeds maximum depth by one component */ input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH + 1); CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); - free(input); + guac_mem_free(input); /* Exactly maximum depth (should still be rejected as SFTP depth limits are * set such that a path with the maximum depth will exceed the maximum * length) */ input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); - free(input); + guac_mem_free(input); /* Less than maximum depth */ input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH - 1); CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); - free(input); + guac_mem_free(input); } diff --git a/src/common-ssh/user.c b/src/common-ssh/user.c index 92c8d963..24c74dce 100644 --- a/src/common-ssh/user.c +++ b/src/common-ssh/user.c @@ -20,15 +20,18 @@ #include "common-ssh/key.h" #include "common-ssh/user.h" +#include +#include + #include #include guac_common_ssh_user* guac_common_ssh_create_user(const char* username) { - guac_common_ssh_user* user = malloc(sizeof(guac_common_ssh_user)); + guac_common_ssh_user* user = guac_mem_alloc(sizeof(guac_common_ssh_user)); /* Init user */ - user->username = strdup(username); + user->username = guac_strdup(username); user->password = NULL; user->private_key = NULL; @@ -43,9 +46,9 @@ void guac_common_ssh_destroy_user(guac_common_ssh_user* user) { guac_common_ssh_key_free(user->private_key); /* Free all other data */ - free(user->password); - free(user->username); - free(user); + guac_mem_free(user->password); + guac_mem_free(user->username); + guac_mem_free(user); } @@ -53,8 +56,8 @@ void guac_common_ssh_user_set_password(guac_common_ssh_user* user, const char* password) { /* Replace current password with given value */ - free(user->password); - user->password = strdup(password); + guac_mem_free(user->password); + user->password = guac_strdup(password); } diff --git a/src/protocols/ssh/client.c b/src/protocols/ssh/client.c index c1ef76ff..b116e6d1 100644 --- a/src/protocols/ssh/client.c +++ b/src/protocols/ssh/client.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -69,7 +70,7 @@ int guac_client_init(guac_client* client) { client->args = GUAC_SSH_CLIENT_ARGS; /* Allocate client instance data */ - guac_ssh_client* ssh_client = calloc(1, sizeof(guac_ssh_client)); + guac_ssh_client* ssh_client = guac_mem_zalloc(sizeof(guac_ssh_client)); client->data = ssh_client; /* Set handlers */ @@ -143,7 +144,7 @@ int guac_ssh_client_free_handler(guac_client* client) { guac_ssh_settings_free(ssh_client->settings); /* Free client structure */ - free(ssh_client); + guac_mem_free(ssh_client); guac_common_ssh_uninit(); return 0; diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index 686ef637..ea890cec 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -25,6 +25,7 @@ #include "settings.h" #include "terminal/terminal.h" +#include #include #include @@ -345,7 +346,7 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, return NULL; } - guac_ssh_settings* settings = calloc(1, sizeof(guac_ssh_settings)); + guac_ssh_settings* settings = guac_mem_zalloc(sizeof(guac_ssh_settings)); /* Read parameters */ settings->hostname = @@ -558,48 +559,48 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, void guac_ssh_settings_free(guac_ssh_settings* settings) { /* Free network connection information */ - free(settings->hostname); - free(settings->host_key); - free(settings->port); + guac_mem_free(settings->hostname); + guac_mem_free(settings->host_key); + guac_mem_free(settings->port); /* Free credentials */ - free(settings->username); - free(settings->password); - free(settings->key_base64); - free(settings->key_passphrase); + guac_mem_free(settings->username); + guac_mem_free(settings->password); + guac_mem_free(settings->key_base64); + guac_mem_free(settings->key_passphrase); /* Free display preferences */ - free(settings->font_name); - free(settings->color_scheme); + guac_mem_free(settings->font_name); + guac_mem_free(settings->color_scheme); /* Free requested command */ - free(settings->command); + guac_mem_free(settings->command); /* Free SFTP settings */ - free(settings->sftp_root_directory); + guac_mem_free(settings->sftp_root_directory); /* Free typescript settings */ - free(settings->typescript_name); - free(settings->typescript_path); + guac_mem_free(settings->typescript_name); + guac_mem_free(settings->typescript_path); /* Free screen recording settings */ - free(settings->recording_name); - free(settings->recording_path); + guac_mem_free(settings->recording_name); + guac_mem_free(settings->recording_path); /* Free terminal emulator type. */ - free(settings->terminal_type); + guac_mem_free(settings->terminal_type); /* Free locale */ - free(settings->locale); + guac_mem_free(settings->locale); /* Free the client timezone. */ - free(settings->timezone); + guac_mem_free(settings->timezone); /* Free Wake-on-LAN settings. */ - free(settings->wol_mac_addr); - free(settings->wol_broadcast_addr); + guac_mem_free(settings->wol_mac_addr); + guac_mem_free(settings->wol_broadcast_addr); /* Free overall structure */ - free(settings); + guac_mem_free(settings); } diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 2ebe0687..05255761 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -256,7 +257,7 @@ void* ssh_client_thread(void* data) { ssh_client->term = guac_terminal_create(client, options); /* Free options struct now that it's been used */ - free(options); + guac_mem_free(options); /* Fail if terminal init failed */ if (ssh_client->term == NULL) { diff --git a/src/protocols/ssh/ssh_agent.c b/src/protocols/ssh/ssh_agent.c index 199c3b58..0afbae09 100644 --- a/src/protocols/ssh/ssh_agent.c +++ b/src/protocols/ssh/ssh_agent.c @@ -24,6 +24,7 @@ #include "ssh_buffer.h" #include +#include #include #include #include @@ -189,7 +190,7 @@ void ssh_auth_agent_callback(LIBSSH2_SESSION *session, ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data; /* Init auth agent */ - ssh_auth_agent* auth_agent = malloc(sizeof(ssh_auth_agent)); + ssh_auth_agent* auth_agent = guac_mem_alloc(sizeof(ssh_auth_agent)); auth_agent->channel = channel; auth_agent->identity = client_data->key; auth_agent->buffer_length = 0; From cf1039845f93d54816bbb9bef2062a1129fcdcb1 Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Sun, 15 Oct 2023 23:25:39 -0700 Subject: [PATCH 10/15] GUACAMOLE-1867: Migrate telnet to new memory management functions. --- src/protocols/telnet/client.c | 5 +++-- src/protocols/telnet/input.c | 5 +++-- src/protocols/telnet/settings.c | 39 +++++++++++++++++---------------- src/protocols/telnet/telnet.c | 3 ++- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/protocols/telnet/client.c b/src/protocols/telnet/client.c index c1085038..ba1f20f4 100644 --- a/src/protocols/telnet/client.c +++ b/src/protocols/telnet/client.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -68,7 +69,7 @@ int guac_client_init(guac_client* client) { client->args = GUAC_TELNET_CLIENT_ARGS; /* Allocate client instance data */ - guac_telnet_client* telnet_client = calloc(1, sizeof(guac_telnet_client)); + guac_telnet_client* telnet_client = guac_mem_zalloc(sizeof(guac_telnet_client)); client->data = telnet_client; /* Init telnet client */ @@ -125,7 +126,7 @@ int guac_telnet_client_free_handler(guac_client* client) { if (telnet_client->settings != NULL) guac_telnet_settings_free(telnet_client->settings); - free(telnet_client); + guac_mem_free(telnet_client); return 0; } diff --git a/src/protocols/telnet/input.c b/src/protocols/telnet/input.c index 02ddc1de..849d1897 100644 --- a/src/protocols/telnet/input.c +++ b/src/protocols/telnet/input.c @@ -23,6 +23,7 @@ #include "telnet.h" #include +#include #include #include #include @@ -79,7 +80,7 @@ int guac_telnet_user_key_handler(guac_user* user, int keysym, int pressed) { "Stopping password prompt search due to user input."); regfree(settings->password_regex); - free(settings->password_regex); + guac_mem_free(settings->password_regex); settings->password_regex = NULL; } @@ -91,7 +92,7 @@ int guac_telnet_user_key_handler(guac_user* user, int keysym, int pressed) { "Stopping username prompt search due to user input."); regfree(settings->username_regex); - free(settings->username_regex); + guac_mem_free(settings->username_regex); settings->username_regex = NULL; } diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index ddffc8e6..11bddbb2 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -24,6 +24,7 @@ #include "settings.h" #include "terminal/terminal.h" +#include #include #include @@ -278,7 +279,7 @@ enum TELNET_ARGS_IDX { /** * Compiles the given regular expression, returning NULL if compilation fails * or of the given regular expression is NULL. The returned regex_t must be - * freed with regfree() AND free(), or with guac_telnet_regex_free(). + * freed with regfree() AND guac_mem_free(), or with guac_telnet_regex_free(). * * @param user * The user who provided the setting associated with the given regex @@ -298,7 +299,7 @@ static regex_t* guac_telnet_compile_regex(guac_user* user, char* pattern) { return NULL; int compile_result; - regex_t* regex = malloc(sizeof(regex_t)); + regex_t* regex = guac_mem_alloc(sizeof(regex_t)); /* Compile regular expression */ compile_result = regcomp(regex, pattern, @@ -308,7 +309,7 @@ static regex_t* guac_telnet_compile_regex(guac_user* user, char* pattern) { if (compile_result != 0) { guac_user_log(user, GUAC_LOG_ERROR, "Regular expression '%s' " "could not be compiled.", pattern); - free(regex); + guac_mem_free(regex); return NULL; } @@ -318,7 +319,7 @@ static regex_t* guac_telnet_compile_regex(guac_user* user, char* pattern) { void guac_telnet_regex_free(regex_t** regex) { if (*regex != NULL) { regfree(*regex); - free(*regex); + guac_mem_free(*regex); *regex = NULL; } } @@ -334,7 +335,7 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, return NULL; } - guac_telnet_settings* settings = calloc(1, sizeof(guac_telnet_settings)); + guac_telnet_settings* settings = guac_mem_zalloc(sizeof(guac_telnet_settings)); /* Read parameters */ settings->hostname = @@ -538,12 +539,12 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, void guac_telnet_settings_free(guac_telnet_settings* settings) { /* Free network connection information */ - free(settings->hostname); - free(settings->port); + guac_mem_free(settings->hostname); + guac_mem_free(settings->port); /* Free credentials */ - free(settings->username); - free(settings->password); + guac_mem_free(settings->username); + guac_mem_free(settings->password); /* Free various regexes */ guac_telnet_regex_free(&settings->username_regex); @@ -552,26 +553,26 @@ void guac_telnet_settings_free(guac_telnet_settings* settings) { guac_telnet_regex_free(&settings->login_failure_regex); /* Free display preferences */ - free(settings->font_name); - free(settings->color_scheme); + guac_mem_free(settings->font_name); + guac_mem_free(settings->color_scheme); /* Free typescript settings */ - free(settings->typescript_name); - free(settings->typescript_path); + guac_mem_free(settings->typescript_name); + guac_mem_free(settings->typescript_path); /* Free screen recording settings */ - free(settings->recording_name); - free(settings->recording_path); + guac_mem_free(settings->recording_name); + guac_mem_free(settings->recording_path); /* Free terminal emulator type. */ - free(settings->terminal_type); + guac_mem_free(settings->terminal_type); /* Free WoL settings. */ - free(settings->wol_mac_addr); - free(settings->wol_broadcast_addr); + guac_mem_free(settings->wol_mac_addr); + guac_mem_free(settings->wol_broadcast_addr); /* Free overall structure */ - free(settings); + guac_mem_free(settings); } diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 3a4c5049..e4e2d916 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -24,6 +24,7 @@ #include "terminal/terminal.h" #include +#include #include #include #include @@ -604,7 +605,7 @@ void* guac_telnet_client_thread(void* data) { telnet_client->term = guac_terminal_create(client, options); /* Free options struct now that it's been used */ - free(options); + guac_mem_free(options); /* Fail if terminal init failed */ if (telnet_client->term == NULL) { From fc6195c67fb55ff7bf127d368c03ef95b4e19b3f Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Sun, 15 Oct 2023 23:27:50 -0700 Subject: [PATCH 11/15] GUACAMOLE-1867: Migrate Kubernetes to new memory management functions. --- src/protocols/kubernetes/client.c | 5 ++-- src/protocols/kubernetes/kubernetes.c | 3 ++- src/protocols/kubernetes/settings.c | 33 ++++++++++++++------------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c index e42466eb..038da287 100644 --- a/src/protocols/kubernetes/client.c +++ b/src/protocols/kubernetes/client.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -120,7 +121,7 @@ int guac_client_init(guac_client* client) { client->args = GUAC_KUBERNETES_CLIENT_ARGS; /* Allocate client instance data */ - guac_kubernetes_client* kubernetes_client = calloc(1, sizeof(guac_kubernetes_client)); + guac_kubernetes_client* kubernetes_client = guac_mem_zalloc(sizeof(guac_kubernetes_client)); client->data = kubernetes_client; /* Set handlers */ @@ -159,7 +160,7 @@ int guac_kubernetes_client_free_handler(guac_client* client) { if (kubernetes_client->settings != NULL) guac_kubernetes_settings_free(kubernetes_client->settings); - free(kubernetes_client); + guac_mem_free(kubernetes_client); return 0; } diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c index 28f71e75..3a75bb2e 100644 --- a/src/protocols/kubernetes/kubernetes.c +++ b/src/protocols/kubernetes/kubernetes.c @@ -28,6 +28,7 @@ #include "url.h" #include +#include #include #include #include @@ -255,7 +256,7 @@ void* guac_kubernetes_client_thread(void* data) { kubernetes_client->term = guac_terminal_create(client, options); /* Free options struct now that it's been used */ - free(options); + guac_mem_free(options); /* Fail if terminal init failed */ if (kubernetes_client->term == NULL) { diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c index fd93509c..5da7d8be 100644 --- a/src/protocols/kubernetes/settings.c +++ b/src/protocols/kubernetes/settings.c @@ -21,6 +21,7 @@ #include "settings.h" #include "terminal/terminal.h" +#include #include #include @@ -255,7 +256,7 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user, } guac_kubernetes_settings* settings = - calloc(1, sizeof(guac_kubernetes_settings)); + guac_mem_zalloc(sizeof(guac_kubernetes_settings)); /* Read hostname */ settings->hostname = @@ -411,35 +412,35 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user, void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) { /* Free network connection information */ - free(settings->hostname); + guac_mem_free(settings->hostname); /* Free Kubernetes pod/container details */ - free(settings->kubernetes_namespace); - free(settings->kubernetes_pod); - free(settings->kubernetes_container); + guac_mem_free(settings->kubernetes_namespace); + guac_mem_free(settings->kubernetes_pod); + guac_mem_free(settings->kubernetes_container); /* Free Kubernetes exec command */ - free(settings->exec_command); + guac_mem_free(settings->exec_command); /* Free SSL/TLS details */ - free(settings->client_cert); - free(settings->client_key); - free(settings->ca_cert); + guac_mem_free(settings->client_cert); + guac_mem_free(settings->client_key); + guac_mem_free(settings->ca_cert); /* Free display preferences */ - free(settings->font_name); - free(settings->color_scheme); + guac_mem_free(settings->font_name); + guac_mem_free(settings->color_scheme); /* Free typescript settings */ - free(settings->typescript_name); - free(settings->typescript_path); + guac_mem_free(settings->typescript_name); + guac_mem_free(settings->typescript_path); /* Free screen recording settings */ - free(settings->recording_name); - free(settings->recording_path); + guac_mem_free(settings->recording_name); + guac_mem_free(settings->recording_path); /* Free overall structure */ - free(settings); + guac_mem_free(settings); } From bbf84f408869af03e99f8f28334a571f1ca95851 Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Mon, 16 Oct 2023 09:03:03 -0700 Subject: [PATCH 12/15] GUACAMOLE-1867: Migrate PulseAudio convenience library to new memory management functions. --- src/pulse/pulse.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pulse/pulse.c b/src/pulse/pulse.c index 2f30b1af..48d79269 100644 --- a/src/pulse/pulse.c +++ b/src/pulse/pulse.c @@ -22,6 +22,7 @@ #include "pulse/pulse.h" #include +#include #include #include #include @@ -312,7 +313,7 @@ guac_pa_stream* guac_pa_stream_alloc(guac_client* client, return NULL; /* Init main loop */ - guac_pa_stream* stream = malloc(sizeof(guac_pa_stream)); + guac_pa_stream* stream = guac_mem_alloc(sizeof(guac_pa_stream)); stream->client = client; stream->audio = audio; stream->pa_mainloop = pa_threaded_mainloop_new(); @@ -347,7 +348,7 @@ void guac_pa_stream_free(guac_pa_stream* stream) { /* Stream now ended */ guac_client_log(stream->client, GUAC_LOG_INFO, "Audio stream finished"); - free(stream); + guac_mem_free(stream); } From 944370bdb6b36ef55e4878f205ee8097c2d690d6 Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Mon, 16 Oct 2023 09:04:51 -0700 Subject: [PATCH 13/15] GUACAMOLE-1867: Migrate guaclog utility to new memory management functions. --- src/guaclog/keydef.c | 15 +++++++++------ src/guaclog/state.c | 7 +++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/guaclog/keydef.c b/src/guaclog/keydef.c index 6068c29c..b9fc1db2 100644 --- a/src/guaclog/keydef.c +++ b/src/guaclog/keydef.c @@ -21,6 +21,9 @@ #include "keydef.h" #include "log.h" +#include +#include + #include #include #include @@ -279,16 +282,16 @@ static guaclog_keydef* guaclog_get_unicode_key(int keysym) { */ static guaclog_keydef* guaclog_copy_key(guaclog_keydef* keydef) { - guaclog_keydef* copy = malloc(sizeof(guaclog_keydef)); + guaclog_keydef* copy = guac_mem_alloc(sizeof(guaclog_keydef)); /* Always copy keysym and name */ copy->keysym = keydef->keysym; - copy->name = strdup(keydef->name); + copy->name = guac_strdup(keydef->name); copy->modifier = keydef->modifier; /* Copy value only if defined */ if (keydef->value != NULL) - copy->value = strdup(keydef->value); + copy->value = guac_strdup(keydef->value); else copy->value = NULL; @@ -322,9 +325,9 @@ void guaclog_keydef_free(guaclog_keydef* keydef) { if (keydef == NULL) return; - free(keydef->name); - free(keydef->value); - free(keydef); + guac_mem_free(keydef->name); + guac_mem_free(keydef->value); + guac_mem_free(keydef); } diff --git a/src/guaclog/state.c b/src/guaclog/state.c index b33bdd76..6b353dd1 100644 --- a/src/guaclog/state.c +++ b/src/guaclog/state.c @@ -22,6 +22,9 @@ #include "log.h" #include "state.h" +#include +#include + #include #include #include @@ -50,7 +53,7 @@ guaclog_state* guaclog_state_alloc(const char* path) { } /* Allocate state */ - guaclog_state* state = (guaclog_state*) calloc(1, sizeof(guaclog_state)); + guaclog_state* state = (guaclog_state*) guac_mem_zalloc(sizeof(guaclog_state)); if (state == NULL) { goto fail_state; } @@ -90,7 +93,7 @@ int guaclog_state_free(guaclog_state* state) { /* Close output file */ fclose(state->output); - free(state); + guac_mem_free(state); return 0; } From 60ae3520ee696f4e5f5d54b496de6fe9fb8ba0cd Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Fri, 20 Oct 2023 14:09:56 -0700 Subject: [PATCH 14/15] GUACAMOLE-1867: Migrate guacenc utility to new memory management functions. --- src/guacenc/buffer.c | 9 +++++---- src/guacenc/cursor.c | 8 +++++--- src/guacenc/display.c | 5 +++-- src/guacenc/ffmpeg-compat.c | 12 +++++++----- src/guacenc/image-stream.c | 14 ++++++++------ src/guacenc/image-stream.h | 6 ++++-- src/guacenc/jpeg.c | 5 +++-- src/guacenc/layer.c | 10 ++++++---- src/guacenc/video.c | 5 +++-- 9 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/guacenc/buffer.c b/src/guacenc/buffer.c index 67fe17fe..eace8aaf 100644 --- a/src/guacenc/buffer.c +++ b/src/guacenc/buffer.c @@ -21,12 +21,13 @@ #include "buffer.h" #include +#include #include #include guacenc_buffer* guacenc_buffer_alloc() { - return calloc(1, sizeof(guacenc_buffer)); + return guac_mem_zalloc(sizeof(guacenc_buffer)); } /** @@ -52,7 +53,7 @@ static void guacenc_buffer_free_image(guacenc_buffer* buffer) { } /* Free image data (previously wrapped by Cairo surface */ - free(buffer->image); + guac_mem_free(buffer->image); buffer->image = NULL; } @@ -65,7 +66,7 @@ void guacenc_buffer_free(guacenc_buffer* buffer) { /* Free buffer and underlying image */ guacenc_buffer_free_image(buffer); - free(buffer); + guac_mem_free(buffer); } @@ -86,7 +87,7 @@ int guacenc_buffer_resize(guacenc_buffer* buffer, int width, int height) { /* Allocate data for new image */ int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); - unsigned char* image = calloc(1, stride*height); + unsigned char* image = guac_mem_zalloc(stride, height); /* Wrap data in surface */ cairo_surface_t* surface = cairo_image_surface_create_for_data(image, diff --git a/src/guacenc/cursor.c b/src/guacenc/cursor.c index d67e9461..e47f44c6 100644 --- a/src/guacenc/cursor.c +++ b/src/guacenc/cursor.c @@ -21,19 +21,21 @@ #include "buffer.h" #include "cursor.h" +#include + #include guacenc_cursor* guacenc_cursor_alloc() { /* Allocate new cursor */ - guacenc_cursor* cursor = (guacenc_cursor*) malloc(sizeof(guacenc_cursor)); + guacenc_cursor* cursor = (guacenc_cursor*) guac_mem_alloc(sizeof(guacenc_cursor)); if (cursor == NULL) return NULL; /* Allocate associated buffer (image) */ cursor->buffer = guacenc_buffer_alloc(); if (cursor->buffer == NULL) { - free(cursor); + guac_mem_free(cursor); return NULL; } @@ -53,7 +55,7 @@ void guacenc_cursor_free(guacenc_cursor* cursor) { /* Free underlying buffer */ guacenc_buffer_free(cursor->buffer); - free(cursor); + guac_mem_free(cursor); } diff --git a/src/guacenc/display.c b/src/guacenc/display.c index 094376cf..e3be0b75 100644 --- a/src/guacenc/display.c +++ b/src/guacenc/display.c @@ -23,6 +23,7 @@ #include "video.h" #include +#include #include @@ -93,7 +94,7 @@ guacenc_display* guacenc_display_alloc(const char* path, const char* codec, /* Allocate display */ guacenc_display* display = - (guacenc_display*) calloc(1, sizeof(guacenc_display)); + (guacenc_display*) guac_mem_zalloc(sizeof(guacenc_display)); /* Associate display with video output */ display->output = video; @@ -131,7 +132,7 @@ int guacenc_display_free(guacenc_display* display) { /* Free cursor */ guacenc_cursor_free(display->cursor); - free(display); + guac_mem_free(display); return retval; } diff --git a/src/guacenc/ffmpeg-compat.c b/src/guacenc/ffmpeg-compat.c index 54e4b749..9f12b5ca 100644 --- a/src/guacenc/ffmpeg-compat.c +++ b/src/guacenc/ffmpeg-compat.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -106,10 +107,11 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) { AVCodecContext* context = video->context; /* Calculate appropriate buffer size */ - int length = FF_MIN_BUFFER_SIZE + 12 * context->width * context->height; + size_t length = guac_mem_ckd_add_or_die(FF_MIN_BUFFER_SIZE, + guac_mem_ckd_mul_or_die(12, context->width, context->height)); /* Allocate space for output */ - uint8_t* data = malloc(length); + uint8_t* data = guac_mem_alloc(length); if (data == NULL) return -1; @@ -118,19 +120,19 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) { if (used < 0) { guacenc_log(GUAC_LOG_WARNING, "Error encoding frame #%" PRId64, video->next_pts); - free(data); + guac_mem_free(data); return -1; } /* Report if no data needs to be written */ if (used == 0) { - free(data); + guac_mem_free(data); return 0; } /* Write data, logging any errors */ guacenc_write_packet(video, data, used); - free(data); + guac_mem_free(data); return 1; #else diff --git a/src/guacenc/image-stream.c b/src/guacenc/image-stream.c index 8789dc16..6b617b5f 100644 --- a/src/guacenc/image-stream.c +++ b/src/guacenc/image-stream.c @@ -29,6 +29,7 @@ #endif #include +#include #include #include @@ -67,7 +68,7 @@ guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index, const char* mimetype, int x, int y) { /* Allocate stream */ - guacenc_image_stream* stream = malloc(sizeof(guacenc_image_stream)); + guacenc_image_stream* stream = guac_mem_alloc(sizeof(guacenc_image_stream)); if (stream == NULL) return NULL; @@ -83,7 +84,7 @@ guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index, /* Allocate initial buffer */ stream->length = 0; stream->max_length = GUACENC_IMAGE_STREAM_INITIAL_LENGTH; - stream->buffer = (unsigned char*) malloc(stream->max_length); + stream->buffer = (unsigned char*) guac_mem_alloc(stream->max_length); return stream; @@ -96,11 +97,12 @@ int guacenc_image_stream_receive(guacenc_image_stream* stream, if (stream->max_length - stream->length < length) { /* Calculate a reasonable new max length guaranteed to fit buffer */ - int new_max_length = stream->max_length * 2 + length; + size_t new_max_length = guac_mem_ckd_add_or_die( + guac_mem_ckd_mul_or_die(stream->max_length, 2), length); /* Attempt to resize buffer */ unsigned char* new_buffer = - (unsigned char*) realloc(stream->buffer, new_max_length); + (unsigned char*) guac_mem_realloc(stream->buffer, new_max_length); if (new_buffer == NULL) return 1; @@ -158,10 +160,10 @@ int guacenc_image_stream_free(guacenc_image_stream* stream) { return 0; /* Free image buffer */ - free(stream->buffer); + guac_mem_free(stream->buffer); /* Free actual stream */ - free(stream); + guac_mem_free(stream); return 0; } diff --git a/src/guacenc/image-stream.h b/src/guacenc/image-stream.h index c73df885..3547fc31 100644 --- a/src/guacenc/image-stream.h +++ b/src/guacenc/image-stream.h @@ -25,6 +25,8 @@ #include +#include + /** * The initial number of bytes to allocate for the image data buffer. If this * buffer is not sufficiently large, it will be dynamically reallocated as it @@ -87,13 +89,13 @@ typedef struct guacenc_image_stream { /** * The number of bytes currently stored in the buffer. */ - int length; + size_t length; /** * The maximum number of bytes that can be stored in the current buffer * before it must be reallocated. */ - int max_length; + size_t max_length; /** * The decoder to use when decoding the raw data received along this diff --git a/src/guacenc/jpeg.c b/src/guacenc/jpeg.c index 4bf655f3..a472ae0b 100644 --- a/src/guacenc/jpeg.c +++ b/src/guacenc/jpeg.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -109,7 +110,7 @@ cairo_surface_t* guacenc_jpeg_decoder(unsigned char* data, int length) { int height = cinfo.output_height; /* Allocate sufficient buffer space for one JPEG scanline */ - unsigned char* jpeg_scanline = malloc(width * 3); + unsigned char* jpeg_scanline = guac_mem_alloc(width, 3); /* Create blank Cairo surface (no transparency in JPEG) */ cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, @@ -135,7 +136,7 @@ cairo_surface_t* guacenc_jpeg_decoder(unsigned char* data, int length) { } /* Scanline buffer is no longer needed */ - free(jpeg_scanline); + guac_mem_free(jpeg_scanline); /* End decompression */ jpeg_finish_decompress(&cinfo); diff --git a/src/guacenc/layer.c b/src/guacenc/layer.c index 0eda10b5..7a81fc59 100644 --- a/src/guacenc/layer.c +++ b/src/guacenc/layer.c @@ -21,19 +21,21 @@ #include "buffer.h" #include "layer.h" +#include + #include guacenc_layer* guacenc_layer_alloc() { /* Allocate new layer */ - guacenc_layer* layer = (guacenc_layer*) calloc(1, sizeof(guacenc_layer)); + guacenc_layer* layer = (guacenc_layer*) guac_mem_zalloc(sizeof(guacenc_layer)); if (layer == NULL) return NULL; /* Allocate associated buffer (width, height, and image storage) */ layer->buffer = guacenc_buffer_alloc(); if (layer->buffer == NULL) { - free(layer); + guac_mem_free(layer); return NULL; } @@ -41,7 +43,7 @@ guacenc_layer* guacenc_layer_alloc() { layer->frame = guacenc_buffer_alloc(); if (layer->frame== NULL) { guacenc_buffer_free(layer->buffer); - free(layer); + guac_mem_free(layer); return NULL; } @@ -67,7 +69,7 @@ void guacenc_layer_free(guacenc_layer* layer) { /* Free underlying buffer */ guacenc_buffer_free(layer->buffer); - free(layer); + guac_mem_free(layer); } diff --git a/src/guacenc/video.c b/src/guacenc/video.c index e2eed51f..1f58158e 100644 --- a/src/guacenc/video.c +++ b/src/guacenc/video.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -138,7 +139,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name, } /* Allocate video structure */ - guacenc_video* video = malloc(sizeof(guacenc_video)); + guacenc_video* video = guac_mem_alloc(sizeof(guacenc_video)); if (video == NULL) goto fail_alloc_video; @@ -503,7 +504,7 @@ int guacenc_video_free(guacenc_video* video) { avcodec_free_context(&(video->context)); } - free(video); + guac_mem_free(video); return 0; } From 7f6cf2021837395126ecd6382b31a51233e2e191 Mon Sep 17 00:00:00 2001 From: Mike Jumper Date: Mon, 23 Oct 2023 14:20:29 -0700 Subject: [PATCH 15/15] GUACAMOLE-1867: Add *_or_die() variant of guac_mem_realloc(). --- src/libguac/guacamole/mem.h | 66 +++++++++++--- src/libguac/guacamole/private/mem.h | 53 +++++++++-- src/libguac/mem.c | 15 ++++ src/libguac/tests/Makefile.am | 1 + src/libguac/tests/mem/realloc_or_die.c | 120 +++++++++++++++++++++++++ src/terminal/buffer.c | 2 +- 6 files changed, 234 insertions(+), 23 deletions(-) create mode 100644 src/libguac/tests/mem/realloc_or_die.c diff --git a/src/libguac/guacamole/mem.h b/src/libguac/guacamole/mem.h index 9a78db97..65468c38 100644 --- a/src/libguac/guacamole/mem.h +++ b/src/libguac/guacamole/mem.h @@ -308,13 +308,13 @@ /** * Reallocates a contiguous block of memory that was previously allocated with - * guac_mem_alloc(), guac_mem_zalloc(), or guac_mem_realloc(), returning a - * pointer to the first byte of that reallocated block of memory. If multiple - * sizes are provided, these sizes are multiplied together to produce the final - * size of the new block. If memory of the specified size cannot be allocated, - * or if multiplying the sizes would result in integer overflow, guac_error is - * set appropriately, the original block of memory is left untouched, and NULL - * is returned. + * guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of their + * *_or_die() variants, returning a pointer to the first byte of that + * reallocated block of memory. If multiple sizes are provided, these sizes are + * multiplied together to produce the final size of the new block. If memory of + * the specified size cannot be allocated, or if multiplying the sizes would + * result in integer overflow, guac_error is set appropriately, the original + * block of memory is left untouched, and NULL is returned. * * This macro is analogous to the standard realloc(), but accepts a list of * size factors instead of a requiring exactly one integer size. @@ -344,11 +344,49 @@ (const size_t[]) { __VA_ARGS__ } \ ) +/** + * Reallocates a contiguous block of memory that was previously allocated with + * guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of their + * *_or_die() variants, returning a pointer to the first byte of that + * reallocated block of memory. If multiple sizes are provided, these sizes are + * multiplied together to produce the final size of the new block. If memory of + * the specified size cannot be allocated, execution of the current process is + * aborted entirely, and this function does not return. + * + * This macro is analogous to the standard realloc(), but accepts a list of + * size factors instead of a requiring exactly one integer size and does not + * return in the event a block cannot be allocated. + * + * The returned pointer may be the same as the original pointer, but this is + * not guaranteed. If the returned pointer is different, the original pointer + * is automatically freed. + * + * The pointer returned by guac_mem_realloc() SHOULD be freed with a subsequent + * call to guac_mem_free(), but MAY instead be freed with a subsequent call to + * free(). + * + * @param ... + * A series of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the reallocated block of memory. If a + * block of memory could not be allocated, execution of the current process + * is aborted, and this function does not return. + */ +#define guac_mem_realloc_or_die(mem, ...) \ + PRIV_guac_mem_realloc_or_die( \ + mem, \ + sizeof((const size_t[]) { __VA_ARGS__ }) / sizeof(const size_t), \ + (const size_t[]) { __VA_ARGS__ } \ + ) + /** * Frees the memory block at the given pointer, which MUST have been allocated - * with guac_mem_alloc(), guac_mem_zalloc(), or guac_mem_realloc(). The pointer - * is automatically assigned a value of NULL after memory is freed. If the - * provided pointer is already NULL, this macro has no effect. + * with guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of + * their *_or_die() variants. The pointer is automatically assigned a value of + * NULL after memory is freed. If the provided pointer is already NULL, this + * macro has no effect. * * @param mem * A pointer to the memory to be freed. @@ -357,10 +395,10 @@ /** * Frees the memory block at the given const pointer, which MUST have been - * allocated with guac_mem_alloc(), guac_mem_zalloc(), or guac_mem_realloc(). - * As the pointer is presumed constant, it is not automatically assigned a - * value of NULL after memory is freed. If the provided pointer is NULL, this - * macro has no effect. + * allocated with guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or + * one of their *_or_die() variants. As the pointer is presumed constant, it is + * not automatically assigned a value of NULL after memory is freed. If the + * provided pointer is NULL, this macro has no effect. * * The guac_mem_free() macro should be used in favor of this macro. This macro * should only be used in cases where a constant pointer is absolutely diff --git a/src/libguac/guacamole/private/mem.h b/src/libguac/guacamole/private/mem.h index 98668e72..dd24f8a0 100644 --- a/src/libguac/guacamole/private/mem.h +++ b/src/libguac/guacamole/private/mem.h @@ -231,12 +231,12 @@ size_t PRIV_guac_mem_ckd_sub_or_die(size_t term_count, const size_t* terms); /** * Reallocates a contiguous block of memory that was previously allocated with * guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of their - * PRIV_guac_*() variants, returning a pointer to the first byte of that - * reallocated block of memory. If multiple sizes are provided, these sizes are - * multiplied together to produce the final size of the new block. If memory of - * the specified size cannot be allocated, or if multiplying the sizes would - * result in integer overflow, guac_error is set appropriately, the original - * block of memory is left untouched, and NULL is returned. + * PRIV_guac_*() or *_or_die() variants, returning a pointer to the first byte + * of that reallocated block of memory. If multiple sizes are provided, these + * sizes are multiplied together to produce the final size of the new block. If + * memory of the specified size cannot be allocated, or if multiplying the + * sizes would result in integer overflow, guac_error is set appropriately, the + * original block of memory is left untouched, and NULL is returned. * * This function is analogous to the standard realloc(), but accepts a list of * size factors instead of a requiring exactly one integer size. @@ -265,11 +265,48 @@ size_t PRIV_guac_mem_ckd_sub_or_die(size_t term_count, const size_t* terms); */ void* PRIV_guac_mem_realloc(void* mem, size_t factor_count, const size_t* factors); +/** + * Reallocates a contiguous block of memory that was previously allocated with + * guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of their + * PRIV_guac_*() or *_or_die() variants, returning a pointer to the first byte + * of that reallocated block of memory. If multiple sizes are provided, these + * sizes are multiplied together to produce the final size of the new block. If + * memory of the specified size cannot be allocated, or if multiplying the + * sizes would result in integer overflow, execution of the current process is + * aborted entirely, and this function does not return. + * + * This function is analogous to the standard realloc(), but accepts a list of + * size factors instead of a requiring exactly one integer size and does not + * return in the event a block cannot be allocated. + * + * The returned pointer may be the same as the original pointer, but this is + * not guaranteed. If the returned pointer is different, the original pointer + * is automatically freed. + * + * The pointer returned by guac_mem_realloc() SHOULD be freed with a subsequent + * call to guac_mem_free() or PRIV_guac_mem_free(), but MAY instead be freed + * with a subsequent call to free(). + * + * @param factor_count + * The number of factors to multiply together to produce the desired block + * size. + * + * @param factors + * An array of one or more size_t values that should be multiplied together + * to produce the desired block size. At least one value MUST be provided. + * + * @returns + * A pointer to the first byte of the reallocated block of memory. If a + * block of memory could not be allocated, execution of the current process + * is aborted, and this function does not return. + */ +void* PRIV_guac_mem_realloc_or_die(void* mem, size_t factor_count, const size_t* factors); + /** * Frees the memory block at the given pointer, which MUST have been allocated * with guac_mem_alloc(), guac_mem_zalloc(), guac_mem_realloc(), or one of - * their PRIV_guac_*() variants. If the provided pointer is NULL, this function - * has no effect. + * their PRIV_guac_*() or *_or_die() variants. If the provided pointer is NULL, + * this function has no effect. * * @param mem * A pointer to the memory to be freed. diff --git a/src/libguac/mem.c b/src/libguac/mem.c index c06c0ff2..2d139ffd 100644 --- a/src/libguac/mem.c +++ b/src/libguac/mem.c @@ -230,6 +230,21 @@ void* PRIV_guac_mem_realloc(void* mem, size_t factor_count, const size_t* factor } +void* PRIV_guac_mem_realloc_or_die(void* mem, size_t factor_count, const size_t* factors) { + + /* Reset any past errors for upcoming error check */ + guac_error = GUAC_STATUS_SUCCESS; + + /* Perform requested resize, aborting the entire process if this cannot be + * done */ + void* resized_mem = PRIV_guac_mem_realloc(mem, factor_count, factors); + if (resized_mem == NULL && guac_error != GUAC_STATUS_SUCCESS) + abort(); + + return resized_mem; + +} + void PRIV_guac_mem_free(void* mem) { free(mem); } diff --git a/src/libguac/tests/Makefile.am b/src/libguac/tests/Makefile.am index 4f2f429a..3596156c 100644 --- a/src/libguac/tests/Makefile.am +++ b/src/libguac/tests/Makefile.am @@ -49,6 +49,7 @@ test_libguac_SOURCES = \ mem/ckd_sub_or_die.c \ mem/free.c \ mem/realloc.c \ + mem/realloc_or_die.c \ mem/zalloc.c \ parser/append.c \ parser/read.c \ diff --git a/src/libguac/tests/mem/realloc_or_die.c b/src/libguac/tests/mem/realloc_or_die.c new file mode 100644 index 00000000..4a244afa --- /dev/null +++ b/src/libguac/tests/mem/realloc_or_die.c @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "assert-signal.h" + +#include +#include +#include + +/** + * Test which verifies that guac_mem_realloc_or_die() returns NULL for all + * inputs involving at least one zero value (reallocation to zero bytes is not + * an error but equivalent freeing the memory). + */ +void test_mem__realloc_or_die_success_zero() { + + void* ptr; + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 0, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 0, 0, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 0, 0, 0, 0, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 1, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 3, 2, 0)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 5, 0, 8, 9)); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + CU_ASSERT_PTR_NULL(guac_mem_realloc_or_die(ptr, 99, 99, 99, 0, 99)); + +} + +/** + * Test which verifies that guac_mem_realloc_or_die() successfully allocates + * blocks of memory for inputs that can reasonably be expected to succeed. + */ +void test_mem__realloc_or_die_success() { + + void* ptr; + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ptr = guac_mem_realloc_or_die(ptr, 123); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ptr = guac_mem_realloc_or_die(ptr, 123, 456); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ptr = guac_mem_realloc_or_die(ptr, 123, 456, 789); + CU_ASSERT_PTR_NOT_NULL(ptr); + guac_mem_free(ptr); + +} + +/** + * Test which verifies that guac_mem_realloc_or_die() fails to allocate blocks of + * memory that exceed the capacity of a size_t. + */ +void test_mem__realloc_or_die_fail_large() { + + void* ptr; + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ASSERT_SIGNALLED(SIGABRT, guac_mem_realloc_or_die(ptr, 123, 456, SIZE_MAX)); + guac_mem_free(ptr); + + ptr = guac_mem_alloc(1); + CU_ASSERT_PTR_NOT_NULL_FATAL(ptr); + ASSERT_SIGNALLED(SIGABRT, guac_mem_realloc_or_die(ptr, SIZE_MAX / 2, SIZE_MAX / 2)); + guac_mem_free(ptr); + +} + diff --git a/src/terminal/buffer.c b/src/terminal/buffer.c index 1d1d7293..a8cc87ce 100644 --- a/src/terminal/buffer.c +++ b/src/terminal/buffer.c @@ -97,7 +97,7 @@ guac_terminal_buffer_row* guac_terminal_buffer_get_row(guac_terminal_buffer* buf /* Expand if necessary */ if (width > buffer_row->available) { buffer_row->available = guac_mem_ckd_mul_or_die(width, 2); - buffer_row->characters = guac_mem_realloc(buffer_row->characters, + buffer_row->characters = guac_mem_realloc_or_die(buffer_row->characters, sizeof(guac_terminal_char), buffer_row->available); }