Presumably because, in case of function parameters, the thinking is that it's the caller's, and not the callee's, responsibility to manage memory for the arguments. If you do need the callee to free the argument upon exit, the workaround is simple enough, just make a local copy of the argument that is adorned by the cleanup attribute.
void func(char *str)
{
loc_str char *str1 = str;
return;
} // now str1 will be free when func exits
Of course, in this case, do not use the cleanup attribute on the argument passed to func()
by the caller, or you'll have a double free on your hands.
For your use case, I'd suggest creating a macro that increments the use count and declares a local variable of type shared_ptr
.
#define SHARED_PTR_GET_ADD_REF(sp_in, sp_name) ++(*sp_in.use_cnt); \
shared_ptr sp_name = sp_in;
Use that macro everywhere you need to increment use count. So your example, with debug statements, would look like this:
#include <stdlib.h>
#include <stdio.h>
struct shared_ptr_s
{
// struct impl_t* inst;
int *use_cnt;
};
typedef struct shared_ptr_s shared_ptr_t; // unadorned type
#define shared_ptr struct shared_ptr_s __attribute__((cleanup(free_shared)))
#define SHARED_PTR_GET_ADD_REF(sp_in, sp_name) ++(*sp_in.use_cnt); \
printf("add use_cnt = %d\n", *sp_in.use_cnt); \
shared_ptr sp_name = sp_in;
void free_shared(struct shared_ptr_s* ptr)
{
if(!ptr) return;
printf("del use_cnt = %d\n", *ptr->use_cnt - 1);
if(0 == --(*ptr->use_cnt)) {
// dtor(ptr->inst);
printf("freeing %p\n", (void *)ptr->use_cnt);
free(ptr->use_cnt);
}
// ptr->inst = 0;
ptr->use_cnt = 0;
}
void func(shared_ptr_t sp)
{
SHARED_PTR_GET_ADD_REF(sp, sp_loc);
return;
}
int main(void)
{
shared_ptr_t sp = { // original type does not use __attribute__(cleanup)
// .inst = ctor(),
.use_cnt = malloc(sizeof(int))
};
SHARED_PTR_GET_ADD_REF(sp, sp_loc);
func(sp_loc);
return 0;
}