Recognise `__attribute__ ((malloc, malloc (fclose, 1)))` in `compiler.has_function_attribute()`
Describe the bug
Meson doesn't have a way to check for whether the compiler supports "malloc attributes with an argument" like __attribute__ ((malloc, malloc (fclose, 1))). Checking for malloc (which is supported as an atribute already) works but gives a false-positive for support on Clang which does not yet support this extended type (https://github.com/llvm/llvm-project/issues/53152).
(The generic, already-supported malloc attribute simply marks a function as a malloc, while with an argument, it indicates how to free memory allocated by it).
Worked around this in https://github.com/OpenRC/openrc/commit/17de4e5dfdf614332091b856bc05837b2e204a5a.
To Reproduce
project('foo', 'c',
version : '0.45',
license: 'BSD-2'
)
cc = meson.get_compiler('c')
# Meson's has_function_attribute doesn't know about GCC's extended
# version (with arguments), so we have to build a test program instead.
#malloc_attribute_test = '''#include<stdlib.h>
#__attribute__ ((malloc (free, 1)))
#int func() { return 0; }
#'''
#if cc.compiles(malloc_attribute_test, name : 'malloc attribute with arguments')
# add_project_arguments('-DHAVE_MALLOC_EXTENDED_ATTRIBUTE', language: 'c')
#endif
if cc.has_function_attribute('malloc')
add_project_arguments('-DHAVE_MALLOC_EXTENDED_ATTRIBUTE', language: 'c')
endif
foolib = shared_library('foo', ['foo.c'])
foo.c:
void *foo_free(void* foo);
#ifdef HAVE_MALLOC_EXTENDED_ATTRIBUTE
__attribute__ ((malloc (foo_free, 1)))
#endif
void *foo_new(void);
The build fails with Clang as HAVE_MALLOC_EXTENDED_ATTRIBUTE is defined when it shouldn't be (has_function_attribute is working correctly, it's just that there's no argument to give it for detecting what I want):
$ CC=clang meson compile -C build
ninja: Entering directory `/tmp/foo2/build'
[1/2] Compiling C object libfoo.so.p/foo.c.o
FAILED: libfoo.so.p/foo.c.o
clang -Ilibfoo.so.p -I. -I.. -fcolor-diagnostics -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -std=c99 -O0 -g -DHAVE_MALLOC_EXTENDED_ATTRIBUTE -fPIC -MD -MQ libfoo.so.p/foo.c.o -MF libfoo.so.p/foo.c.o.d -o libfoo.so.p/foo.c.o -c ../foo.c
../foo.c:4:17: error: 'malloc' attribute takes no arguments
__attribute__ ((malloc (foo_free, 1)))
^
1 error generated.
ninja: build stopped: subcommand failed.
Expected behavior
compiler.has_function_attribute() should allow specifying malloc-with-argument or similar to detect new enough GCC versions which support this and exclude Clang.
system parameters
- Plain native build.
- Gentoo (rolling).
- Python 3.10.6
-
meson --version: 0.63.1 -
ninja --version: 1.11.0
I would look at the visibility:xxx attributes for inspiration on how to name your function attribute since malloc is already taken.
See e.g. commit 5d438b6aedbb074c06f6f9fa2f7972b422ccd1bd for general guidance on how to implement new options for has_function_attribute.
The visibility:xxx method doesn't seem all that scalable. Here is the code I wrote just now for checking attributes for NumPy (there are quite a few more targets):
# Optional compiler attributes
optional_function_attributes = [
['optimize("unroll-loops")', 'OPTIMIZE_UNROLL_LOOPS'],
['optimize("O3")', 'OPTIMIZE_OPT_3'],
['optimize("O2")', 'OPTIMIZE_OPT_2'],
['optimize("nonnull (1)")', 'NONNULL'],
]
if host_machine.cpu_family() in ['x86', 'x86_64']
optional_function_attributes += [
['target("avx")', 'TARGET_AVX'],
['target("avx2")', 'TARGET_AVX2'],
['target("avx512f")', 'TARGET_AVX512F'],
['target("avx512f,avx512dq,avx512bw,avx512vl,avx512cd")', 'TARGET_AVX512_SKX'],
]
endif
foreach attr: optional_function_attributes
if cc.has_function_attribute(attr[0])
cdata.set10('HAVE_ATTRIBUTE_' + attr[1], true)
endif
endforeach
It seems like for (malloc, malloc (xxx, 1)), optimize("xxx") and target("xxx"), the list of things to check can be arbitrarily long. Would it make sense to allow:
cc.has_function_attribute('malloc:xxx')
cc.has_function_attribute('optimize:xxx')
cc.has_function_attribute('target:xxx')
where xxx can be arbitrary and just does the right thing?
Or should that use cc.compiles instead? If so, where's the line for what to add as builtin attributes?
I think that either allowing malloc:xxx where xxx is an arbatrary thing, or cc.has_function_attribute('malloc', arguments : 'foo_free, 1') would be fine solutions. There are obviously advantages to both, so I'm not sure which would be better.
In the latter case you'd have to do some interpreter validation, which stinks
The visibility was kinda a hack because macos... It really only works because the chances of getting any sort of new visibility is very low
I like the arguments variant better. Seems more forward compatible.