mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-10-21 07:45:02 +02:00

If (u)intptr_t exist, the only guarantee provided by the C standard is that you can cast a pointer to one and back. No claims are made about what that injective pointer-to-integer mapping is, nor the surjective reverse integer-to-pointer mapping; for example, nowhere is it specified that, given a char *p, p + 1 == (char *)((uintptr_t)p + 1), although no sensible implementation would make that not the case (provided p is a valid strictly in bounds pointer). With real pointers, taking them out of bounds (other than the one exception that is a one-past-the-end pointer) of their corresponding allocation is UB. Whilst the semantics of arithmetic on uintptr_t is not specified when cast back to a pointer, compilers already assume that uintptr_t arithmetic does not go out of bounds (or, put another way, that the result always ends up pointing to the same allocation) and their alias analysis-based optimisations already assume this. CHERI, and Arm's Morello, implement C language pointers with hardware capabilities, which are unforgeable pointers with bounds and permissions. In order to only double rather than quadruple the size of pointers, CHERI exploits C's requirement that pointers not be taken out of bounds, and compresses these bounds using a floating-point-like representation. The important implication of this for most software is that if a capability, i.e. C pointer in CHERI C, is taken too far out of bounds (where "too far" is proportional to the size of the allocation) it can no longer be represented and thus is invalidated, meaning it will trap on a later dereference. This also extends to (u)intptr_t, which are also implemented as capabilities, since if it were just a plain integer then casting a pointer to (u)intptr_t would lose the metadata and break the ability to cast back to a pointer. Whilst the composition of dividing a pointer and then multiplying it again has a somewhat sensible interpretation of rounding it down (even though technically no such guarantees are made by the spec), the individual operations do not, and the division is highly likely to take the pointer far out of bounds of its allocation and, on CHERI, result in it being unrepresentable and thus invalidated. Instead, we can perform a more standard bitwise AND with a mask to clear the low bits, exploiting the fact that alignments are powers of two; note that technically the rounding up variant of this does take the pointer out of bounds slightly and, whilst there are other ways to write such code that avoid doing so, they are more cumbersome, and this code does not need to worry about that.
164 lines
3.8 KiB
C
164 lines
3.8 KiB
C
/*
|
|
* MessagePack for C memory pool implementation
|
|
*
|
|
* Copyright (C) 2008-2010 FURUHASHI Sadayuki
|
|
*
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
#ifndef MSGPACK_ZONE_H
|
|
#define MSGPACK_ZONE_H
|
|
|
|
#include "sysdep.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
/**
|
|
* @defgroup msgpack_zone Memory zone
|
|
* @ingroup msgpack
|
|
* @{
|
|
*/
|
|
|
|
typedef struct msgpack_zone_finalizer {
|
|
void (*func)(void* data);
|
|
void* data;
|
|
} msgpack_zone_finalizer;
|
|
|
|
typedef struct msgpack_zone_finalizer_array {
|
|
msgpack_zone_finalizer* tail;
|
|
msgpack_zone_finalizer* end;
|
|
msgpack_zone_finalizer* array;
|
|
} msgpack_zone_finalizer_array;
|
|
|
|
struct msgpack_zone_chunk;
|
|
typedef struct msgpack_zone_chunk msgpack_zone_chunk;
|
|
|
|
typedef struct msgpack_zone_chunk_list {
|
|
size_t free;
|
|
char* ptr;
|
|
msgpack_zone_chunk* head;
|
|
} msgpack_zone_chunk_list;
|
|
|
|
typedef struct msgpack_zone {
|
|
msgpack_zone_chunk_list chunk_list;
|
|
msgpack_zone_finalizer_array finalizer_array;
|
|
size_t chunk_size;
|
|
} msgpack_zone;
|
|
|
|
#ifndef MSGPACK_ZONE_CHUNK_SIZE
|
|
#define MSGPACK_ZONE_CHUNK_SIZE 8192
|
|
#endif
|
|
|
|
MSGPACK_DLLEXPORT
|
|
bool msgpack_zone_init(msgpack_zone* zone, size_t chunk_size);
|
|
MSGPACK_DLLEXPORT
|
|
void msgpack_zone_destroy(msgpack_zone* zone);
|
|
|
|
MSGPACK_DLLEXPORT
|
|
msgpack_zone* msgpack_zone_new(size_t chunk_size);
|
|
MSGPACK_DLLEXPORT
|
|
void msgpack_zone_free(msgpack_zone* zone);
|
|
|
|
static inline void* msgpack_zone_malloc(msgpack_zone* zone, size_t size);
|
|
static inline void* msgpack_zone_malloc_no_align(msgpack_zone* zone, size_t size);
|
|
|
|
static inline bool msgpack_zone_push_finalizer(msgpack_zone* zone,
|
|
void (*func)(void* data), void* data);
|
|
|
|
static inline void msgpack_zone_swap(msgpack_zone* a, msgpack_zone* b);
|
|
|
|
MSGPACK_DLLEXPORT
|
|
bool msgpack_zone_is_empty(msgpack_zone* zone);
|
|
|
|
MSGPACK_DLLEXPORT
|
|
void msgpack_zone_clear(msgpack_zone* zone);
|
|
|
|
/** @} */
|
|
|
|
|
|
#ifndef MSGPACK_ZONE_ALIGN
|
|
#define MSGPACK_ZONE_ALIGN sizeof(void*)
|
|
#endif
|
|
|
|
MSGPACK_DLLEXPORT
|
|
void* msgpack_zone_malloc_expand(msgpack_zone* zone, size_t size);
|
|
|
|
static inline void* msgpack_zone_malloc_no_align(msgpack_zone* zone, size_t size)
|
|
{
|
|
char* ptr;
|
|
msgpack_zone_chunk_list* cl = &zone->chunk_list;
|
|
|
|
if(zone->chunk_list.free < size) {
|
|
return msgpack_zone_malloc_expand(zone, size);
|
|
}
|
|
|
|
ptr = cl->ptr;
|
|
cl->free -= size;
|
|
cl->ptr += size;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
static inline void* msgpack_zone_malloc(msgpack_zone* zone, size_t size)
|
|
{
|
|
char* aligned =
|
|
(char*)(
|
|
(uintptr_t)(
|
|
zone->chunk_list.ptr + (MSGPACK_ZONE_ALIGN - 1)
|
|
) & ~(uintptr_t)(MSGPACK_ZONE_ALIGN - 1)
|
|
);
|
|
size_t adjusted_size = size + (size_t)(aligned - zone->chunk_list.ptr);
|
|
if(zone->chunk_list.free >= adjusted_size) {
|
|
zone->chunk_list.free -= adjusted_size;
|
|
zone->chunk_list.ptr += adjusted_size;
|
|
return aligned;
|
|
}
|
|
{
|
|
void* ptr = msgpack_zone_malloc_expand(zone, size + (MSGPACK_ZONE_ALIGN - 1));
|
|
if (ptr) {
|
|
return (char*)((uintptr_t)(ptr) & ~(uintptr_t)(MSGPACK_ZONE_ALIGN - 1));
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
bool msgpack_zone_push_finalizer_expand(msgpack_zone* zone,
|
|
void (*func)(void* data), void* data);
|
|
|
|
static inline bool msgpack_zone_push_finalizer(msgpack_zone* zone,
|
|
void (*func)(void* data), void* data)
|
|
{
|
|
msgpack_zone_finalizer_array* const fa = &zone->finalizer_array;
|
|
msgpack_zone_finalizer* fin = fa->tail;
|
|
|
|
if(fin == fa->end) {
|
|
return msgpack_zone_push_finalizer_expand(zone, func, data);
|
|
}
|
|
|
|
fin->func = func;
|
|
fin->data = data;
|
|
|
|
++fa->tail;
|
|
|
|
return true;
|
|
}
|
|
|
|
static inline void msgpack_zone_swap(msgpack_zone* a, msgpack_zone* b)
|
|
{
|
|
msgpack_zone tmp = *a;
|
|
*a = *b;
|
|
*b = tmp;
|
|
}
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* msgpack/zone.h */
|