Skip to content

Add type-aware allocator functions to the default allocator#87

Open
QuietMisdreavus wants to merge 9 commits into
gfmfrom
vgm/typed-allocators
Open

Add type-aware allocator functions to the default allocator#87
QuietMisdreavus wants to merge 9 commits into
gfmfrom
vgm/typed-allocators

Conversation

@QuietMisdreavus
Copy link
Copy Markdown

Resolves rdar://170007028

This PR adapts swift-cmark to use type-aware memory allocators in its default allocator set. This required a significant divergence from upstream, due to the requirements for the automatic typed-memory allocator annotations: They can't be applied to function pointers. This means that all the calls to cmark_mem methods needed to be reworked into standalone functions so that the swap for the type-aware version could occur.

Implementation

This PR adds two new fields to cmark_mem: calloc_typed and realloc_typed, that take the same arguments as their untyped counterparts, plus a new cmark_malloc_type_id that denotes a type ID. When typed memory operations are enabled, this is typedef'd to malloc_type_id_t for compatibility with the system type-aware allocators; otherwise it is typedef'd to unsigned long long, which is the current underlying type on macOS and is selected to ensure they are the same size.

In addition, there is a new mem.h header that defines five functions. These are freestanding functions that do nothing but call their associated method in the given cmark_mem instance, but the calloc and realloc functions have an annotation to allow for the typed-memory allocator substitution to occur so that the type-aware allocators can be called when available. (They also introduce a handful of convenience macros to make calling them easier, and ensures that type information is available since they always use the functions with a sizeof and a cast.)

To facilitate the use of these methods and to increase the security of swift-cmark, i've updated the CMake configuration and the Swift package spec to include the -ftyped-memory-operations flag when available, as well as the -Wallocator-wrappers flag (which still triggers on these allocator wrappers due to a bug, heh). I limited the SwiftPM updates to a new package spec that requires Swift 6.3, since my testing with 6.2 indicated that its associated Clang didn't have both flags available. I was able to build it with the Xcode 26.4 beta and it seems like everything works, so unless there's something wrong on non-Apple platforms we should be able to keep it.

Finally, the biggest thing this PR does is replace all the calls to cmark_mem methods to use the mem.h freestanding functions, so that the type-aware memory allocators can be used throughout the library. (I added a freestanding function for free even though we don't have a type-aware implementation of that - there is a malloc_type_free in the headers on macOS but i'm not sure how to wire that one up. 😅)

in order for the typed memory operations use of typed allocators to
work, calls to allocator functions need to be decorated with the
_MALLOC_TYPED attribute. since cmark accesses its allocator wrappers
through function pointers and the cmark_mem struct, this commit adds the
groundwork necessary to allow the typed allocator wrappers to be called
correctly.
Copy link
Copy Markdown

@ojhunt ojhunt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be set up to work correctly with the typed allocators, but I can't comment on the style/design, etc for swift/cmark itself

Comment thread src/cmark.c Outdated
Comment thread src/arena.c Outdated
Comment thread src/include/mem.h Outdated
Copy link
Copy Markdown

@snprajwal snprajwal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly looks good, some minor concerns. Thanks for working on this!

Comment thread src/include/mem.h Outdated
Comment thread src/include/mem.h
Comment on lines +17 to +25
CMARK_GFM_EXPORT
void *cmark_mem_calloc_typed(cmark_mem *mem, size_t count, size_t size, cmark_malloc_type_id type_id);

#define cmark_mem_calloc_typed_backdeploy cmark_mem_calloc_typed

CMARK_GFM_EXPORT
void *cmark_mem_realloc_typed(cmark_mem *mem, void *ptr, size_t size, cmark_malloc_type_id type_id);

#define cmark_mem_realloc_typed_backdeploy cmark_mem_realloc_typed
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both these functions are gated behind _MALLOC_TYPE_ENABLED in mem.c, they would be declared but undefined symbols on platforms that don't define the macro.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, i didn't account for when the feature isn't present. 🤦‍♀️ I can write up fallbacks so that these symbols resolve correctly.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the fallbacks. However, that still means that these symbols are available on platforms that don't define the macro, and passthrough to the untyped version. It would be cleaner for us to instead gate these declarations behind the macro so that the symbol is not available on platforms where it can't be used.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't too keen on completely deleting the functions when typed allocators aren't available, but i guess they're not being directly called anyway, so i pushed up a commit moving the definitions into the guard.

Comment thread src/include/cmark-gfm.h
Now that the wrappers are added to the type-aware allocator machinery,
we can silence the allocator wrapper warning (which still fires here) to
prevent future false-positives.
Comment thread src/mem.c Outdated
Comment on lines +32 to +42
#else

void *cmark_mem_calloc_typed(cmark_mem *mem, size_t count, size_t size, cmark_malloc_type_id type_id) {
return cmark_mem_calloc(mem, count, size);
}

void *cmark_mem_realloc_typed(cmark_mem *mem, void *ptr, size_t size, cmark_malloc_type_id type_id) {
return cmark_mem_realloc(mem, ptr, size);
}

#endif
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref the comment in the header file: we can remove this and instead gate the declarations behind #if defined(_MALLOC_TYPE_ENABLED) && _MALLOC_TYPE_ENABLED

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants