__attribute__((alloc_size(foo))

Hi,

Please find in attach a patch that implements the attribute alloc_size. This attribute was introduced with GCC 4.3.

Intended usage:

void* my_malloc(size_t) __attribute__((alloc_size(1)));
void* my_calloc(size_t, size_t) __attribute__((alloc_size(1,2)));
void* my_realloc(void*, size_t) __attribute__((alloc_size(2)));

The attribute basically declares that a function returns memory of size given by the product of the parameters listed in the attribute.

More info: Function Attributes (Using the GNU Compiler Collection (GCC))

This patch only adds Sema support for the attribute. Wiring for codegen and static analyzer will come later.

Any comments, suggestions, etc?

Thanks,
Nuno

P.S.: This attribute is not expressive enough for functions that e.g. return x elements, like 'alloc_foo_objects(int howmany)'. However, since gcc already has this attribute and software out there is already using it, I think we should support it, even if we come up with a better attribute later.

alloc_size_attr.txt (4.63 KB)

Hi,

Please find in attach a patch that implements the attribute alloc_size. This attribute was introduced with GCC 4.3.

Intended usage:

void* my_malloc(size_t) attribute((alloc_size(1)));
void* my_calloc(size_t, size_t) attribute((alloc_size(1,2)));
void* my_realloc(void*, size_t) attribute((alloc_size(2)));

The attribute basically declares that a function returns memory of size given by the product of the parameters listed in the attribute.

I’ll throw my two cents in and say that this feature would also be useful for projects like SAFECode that, in general, will work with any language but need to know specific information about memory allocators (including a way to determine the size of the allocation).

That said, we need a way to represent this information within the LLVM IR in order for it to be useful.

– John T.

Xi Wang took a stab at this back in February but no one finished reviewing his patch.[1][2] I'll take a look at yours soon, but maybe Xi has an opinion as well?

Jordy

P.S. If we want to go really crazy, alloc_foo_objects(int howmany) could be handled with an extension to alloc_size: __attribute__((alloc_size(1,sizeof(struct foo)))). But that can wait for later.

[1]: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20120227/054264.html
[2]: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-February/019952.html

Hi,

Ah, that's unfortunate; I completely missed Xi Wang's patches.
They are both pretty similar in code and in functionality, though.

Nuno

P.S.: Actually I like you proposal to accept sizeof exprs on par with argument numbers. But I agree, let's get this patch in first, and extend it later.

Citando Jordan Rose <jediknil@belkadan.com>:

This is /very/ similar to Xi's code! ...

Your patch allows users to use any number of arguments for alloc_size; we should at least have a warning case for 0, but do we want to allow more than 2? (I see no reason not to except that we have to be very careful handling overflow, but "simplicity" isn't a bad reason, and we could always change it later.)

If we do go with just two args, I would suggest messing with Attr.td's tablegen to add a DefaultUnsignedArgument, so you can use [UnsignedArgument<"First">, DefaultUnsignedArgument<"Second",1>] instead of [VariadicUnsignedArgument<"Args">].

+ // check if the function argument is of an integer type
+ QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+ if (!T->isIntegerType()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "alloc_size" << x+1 << Ex->getSourceRange();
+ continue;
+ }

Why continue here? We have to make sure not to attach the attribute if any argument fails anyway, or we might get weird errors in Sema later on.

Eli's comments on the original patch apply here too:

+ unsigned* start = &AllocSizeArgs[0];
+ unsigned size = AllocSizeArgs.size();
+ llvm::array_pod_sort(start, start + size);

Don't you need to check for duplicates? Also, for an alloc_size
attribute which doesn't specify any indexes?

+ // Is the function argument an integer type?
+ QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();

I don't think you want to allow applying alloc_size to arguments of type "int&".

+ unsigned x = (unsigned) ArgNum.getZExtValue();

This is unsafe; there's no guarantee ArgNum fits into a 64-bit integer
(which will cause an assert), and you're masking off the top 32 bits
of that 64-bit integer without any additional checks. You should
perform the bounds checking on the APSInt, and then perform whatever
conversion is necessary. (And if this is copied from existing cod
which does the same thing, please fix that as well.)

Xi's second iteration addresses these concerns, noting that handleNonNullAttr() has the same problems.

Other than that it looks fairly good, and sorry, Xi, yours was fairly good too, if a little different. I can't see why this shouldn't go in after cleanup.

Jordy

Alright, I'll commit a cleaned up version in a minute.

Thanks for your review!
Nuno

Citando Jordy Rose <jediknil@belkadan.com>:

Jordy,

Thanks for letting me know. I am happy to see alloc_size in Clang. :wink:

Also thanks to Nuno for bringing this up.

- xi

It's in:
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20120521/058005.html

Thank you both,
Nuno

Citando Xi Wang <xi.wang@gmail.com>: