cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

mem.c (6983B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "guacamole/error.h"
     21#include "guacamole/mem.h"
     22#include "guacamole/private/mem.h"
     23
     24#include <stddef.h>
     25#include <stdint.h>
     26#include <stdlib.h>
     27
     28/*
     29 * ============================================================================
     30 *
     31 * IMPORTANT: For compatibility with past usages of libguac, all allocation
     32 * functions implemented here need to remain compatible with the standard
     33 * free() function, as there are past usages of libguac functions that expect
     34 * allocated memory to have been allocated with malloc() or similar. Some good
     35 * examples of this would be guac_strdup() or guac_user_parse_args_string().
     36 *
     37 * It is OK if these allocation functions add new functionality beyond what
     38 * malloc() provides, but care must be taken to ensure free() can still be used
     39 * safely and without leaks, even if guac_mem_free() will always be preferred.
     40 *
     41 * It is further OK for guac_mem_free() to be incompatible with free() and only
     42 * usable on memory blocks allocated through guac_mem_alloc() and similar.
     43 *
     44 * ============================================================================
     45 */
     46
     47int PRIV_guac_mem_ckd_mul(size_t* result, size_t factor_count, const size_t* factors) {
     48
     49    /* Consider calculation invalid if no factors are provided at all */
     50    if (factor_count == 0)
     51        return 1;
     52
     53    /* Multiply all provided factors together */
     54    size_t size = *(factors++);
     55    while (--factor_count && size) {
     56
     57        size_t factor = *(factors++);
     58
     59        /* Fail if including this additional factor would exceed SIZE_MAX */
     60        size_t max_factor = SIZE_MAX / size;
     61        if (factor > max_factor)
     62            return 1;
     63
     64        size *= factor;
     65
     66    }
     67
     68    *result = size;
     69    return 0;
     70
     71}
     72
     73int PRIV_guac_mem_ckd_add(size_t* result, size_t term_count, const size_t* terms) {
     74
     75    /* Consider calculation invalid if no terms are provided at all */
     76    if (term_count == 0)
     77        return 1;
     78
     79    /* Multiply all provided terms together */
     80    size_t size = *(terms++);
     81    while (--term_count) {
     82
     83        size_t term = *(terms++);
     84
     85        /* Fail if including this additional term would exceed SIZE_MAX */
     86        size_t max_term = SIZE_MAX - size;
     87        if (term > max_term)
     88            return 1;
     89
     90        size += term;
     91
     92    }
     93
     94    *result = size;
     95    return 0;
     96
     97}
     98
     99int PRIV_guac_mem_ckd_sub(size_t* result, size_t term_count, const size_t* terms) {
    100
    101    /* Consider calculation invalid if no terms are provided at all */
    102    if (term_count == 0)
    103        return 1;
    104
    105    /* Multiply all provided terms together */
    106    size_t size = *(terms++);
    107    while (--term_count) {
    108
    109        size_t term = *(terms++);
    110
    111        /* Fail if including this additional term would wrap past zero */
    112        if (term > size)
    113            return 1;
    114
    115        size -= term;
    116
    117    }
    118
    119    *result = size;
    120    return 0;
    121
    122}
    123
    124size_t PRIV_guac_mem_ckd_mul_or_die(size_t factor_count, const size_t* factors) {
    125
    126    /* Perform request multiplication, aborting the entire process if the
    127     * calculation overflows */
    128    size_t result = 0;
    129    if (PRIV_guac_mem_ckd_mul(&result, factor_count, factors))
    130        abort();
    131
    132    return result;
    133
    134}
    135
    136size_t PRIV_guac_mem_ckd_add_or_die(size_t term_count, const size_t* terms) {
    137
    138    /* Perform request addition, aborting the entire process if the calculation
    139     * overflows */
    140    size_t result = 0;
    141    if (PRIV_guac_mem_ckd_add(&result, term_count, terms))
    142        abort();
    143
    144    return result;
    145
    146}
    147
    148size_t PRIV_guac_mem_ckd_sub_or_die(size_t term_count, const size_t* terms) {
    149
    150    /* Perform request subtraction, aborting the entire process if the
    151     * calculation overflows */
    152    size_t result = 0;
    153    if (PRIV_guac_mem_ckd_sub(&result, term_count, terms))
    154        abort();
    155
    156    return result;
    157
    158}
    159
    160void* PRIV_guac_mem_alloc(size_t factor_count, const size_t* factors) {
    161
    162    size_t size = 0;
    163
    164    if (PRIV_guac_mem_ckd_mul(&size, factor_count, factors)) {
    165        guac_error = GUAC_STATUS_NO_MEMORY;
    166        return NULL;
    167    }
    168    else if (size == 0)
    169        return NULL;
    170
    171    void* mem = malloc(size);
    172    if (mem == NULL) {
    173        /* C does not require that malloc() set errno (though POSIX does). For
    174         * portability, we set guac_error here regardless of the underlying
    175         * behavior of malloc(). */
    176        guac_error = GUAC_STATUS_NO_MEMORY;
    177    }
    178
    179    return mem;
    180
    181}
    182
    183void* PRIV_guac_mem_zalloc(size_t factor_count, const size_t* factors) {
    184
    185    size_t size = 0;
    186
    187    if (PRIV_guac_mem_ckd_mul(&size, factor_count, factors)) {
    188        guac_error = GUAC_STATUS_NO_MEMORY;
    189        return NULL;
    190    }
    191    else if (size == 0)
    192        return NULL;
    193
    194    void* mem = calloc(1, size);
    195    if (mem == NULL) {
    196        /* C does not require that calloc() set errno (though POSIX does). For
    197         * portability, we set guac_error here regardless of the underlying
    198         * behavior of calloc(). */
    199        guac_error = GUAC_STATUS_NO_MEMORY;
    200    }
    201
    202    return mem;
    203
    204}
    205
    206void* PRIV_guac_mem_realloc(void* mem, size_t factor_count, const size_t* factors) {
    207
    208    size_t size = 0;
    209
    210    if (PRIV_guac_mem_ckd_mul(&size, factor_count, factors)) {
    211        guac_error = GUAC_STATUS_NO_MEMORY;
    212        return NULL;
    213    }
    214
    215    /* Resize to 0 is equivalent to free() */
    216    if (size == 0) {
    217        guac_mem_free(mem);
    218        return NULL;
    219    }
    220
    221    void* resized_mem = realloc(mem, size);
    222    if (resized_mem == NULL) {
    223        /* C does not require that realloc() set errno (though POSIX does). For
    224         * portability, we set guac_error here regardless of the underlying
    225         * behavior of realloc(). */
    226        guac_error = GUAC_STATUS_NO_MEMORY;
    227    }
    228
    229    return resized_mem;
    230
    231}
    232
    233void* PRIV_guac_mem_realloc_or_die(void* mem, size_t factor_count, const size_t* factors) {
    234
    235    /* Reset any past errors for upcoming error check */
    236    guac_error = GUAC_STATUS_SUCCESS;
    237
    238    /* Perform requested resize, aborting the entire process if this cannot be
    239     * done */
    240    void* resized_mem = PRIV_guac_mem_realloc(mem, factor_count, factors);
    241    if (resized_mem == NULL && guac_error != GUAC_STATUS_SUCCESS)
    242        abort();
    243
    244    return resized_mem;
    245
    246}
    247
    248void PRIV_guac_mem_free(void* mem) {
    249    free(mem);
    250}
    251