diff --git a/cdb.h b/cdb.h index 43d58e6..400be19 100644 --- a/cdb.h +++ b/cdb.h @@ -47,7 +47,7 @@ int cdb_firstkey(struct cdb * restrict c,uint32 * restrict kpos); att_write(1) int cdb_nextkey(struct cdb * restrict c,uint32 * restrict kpos); -__bufin(2,3) +__bufin_ornull(2,3) int cdb_successor(struct cdb * restrict c, const unsigned char * restrict buf, size_t len); #define cdb_datapos(c) ((c)->dpos) diff --git a/compiler.h b/compiler.h index e98e383..ddad832 100644 --- a/compiler.h +++ b/compiler.h @@ -1,5 +1,5 @@ -#ifndef LIBOWFAT_ATTRIBUTES_H -#define LIBOWFAT_ATTRIBUTES_H +#ifndef LIBOWFAT_COMPILER_H +#define LIBOWFAT_COMPILER_H // This is here so you can use inline with older gcc versions #if __GNUC__ && (__STDC_VERSION__ < 199901L) @@ -160,55 +160,68 @@ #ifndef __dietlibc__ #if defined(__GNUC__) -#if __has_attribute(null_terminated_string_arg) + +#if !__has_attribute(null_terminated_string_arg) +#define null_terminated_string_arg(a) +#endif + +#if !__has_attribute(nonnull_if_nonzero) +#define nonnull_if_nonzero(idx,szidx) +#endif + +#if __has_attribute(access) +#define __access(a,b) access(a,b) +#define __access3(a,b,c) access(a,b,c) +#else +#define __access(a,b) +#define __access3(a,b,c) +#endif + // Function arguments. // __strin: Argument idx (counted left to right from 1) is a non-NULL string the function reads -#define __strin(idx) __attribute__((nonnull(idx),access(read_only,idx),null_terminated_string_arg(idx))) +#define __strin(idx) __attribute__((nonnull(idx),__access(read_only,idx),null_terminated_string_arg(idx))) // __strnin: Argument idx (counted left to right from 1) is a non-NULL string the function reads, length limit in array elements given in the szidx'th argument -#define __strnin(idx,szidx) __attribute__((nonnull(idx),access(read_only,idx,szidx),null_terminated_string_arg(idx))) +#define __strnin(idx,szidx) __attribute__((nonnull(idx),__access3(read_only,idx,szidx))) +// __strnin_ornull: like _strnin but if length is 0, ptr can be NULL +#define __strnin_ornull(idx,szidx) __attribute__((nonnull_if_nonzero(idx,szidx),__access3(read_only,idx,szidx))) // __bufin: Argument idx (counted left to right from 1) is a non-NULL buffer the function reads from, length limit in array elements given in the szidx'th argument -#define __bufin(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_only,bufidx,szidx))) +#define __bufin(bufidx,szidx) __attribute__((nonnull(bufidx),__access3(read_only,bufidx,szidx))) +// __bufin_ornull: like __bufin but if length is 0, ptr can be NULL +#define __bufin_ornull(bufidx,szidx) __attribute__((nonnull_if_nonzero(bufidx,szidx),__access3(read_only,bufidx,szidx))) // __strout: Argument idx (counted left to right from 1) is a non-NULL string the function writes // Currently we can't tell the compiler that the output will be 0-terminated. -#define __strout(idx) __attribute__((nonnull(idx),access(write_only,idx))) +#define __strout(idx) __attribute__((nonnull(idx),__access(write_only,idx))) // __strnout: Argument idx (counted left to right from 1) is a non-NULL string the function writes, buffer size given in szidx'th function argument (in array elements, not necessarily bytes) // Currently we can't tell the compiler that the output will be 0-terminated. -#define __strnout(idx,szidx) __attribute__((nonnull(idx),access(write_only,idx,szidx))) +#define __strnout(idx,szidx) __attribute__((nonnull(idx),__access3(write_only,idx,szidx))) // __bufout: Argument idx (counted left to right from 1) is a non-NULL buffer the function writes, buffer size given in szidx'th function argument (in array elements, not necessarily bytes) -#define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx),access(write_only,bufidx,szidx))) +#define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx),__access3(write_only,bufidx,szidx))) // __strinout: Argument idx (counted left to right from 1) is a non-NULL string the function reads and writes // Currently we can't tell the compiler that the output will be 0-terminated. -#define __strinout(idx) __attribute__((nonnull(idx),access(read_write,idx),null_terminated_string_arg(idx))) +#define __strinout(idx) __attribute__((nonnull(idx),__access(read_write,idx),null_terminated_string_arg(idx))) // __strninout: Argument idx (counted left to right from 1) is a non-NULL string the function reads and writes, buffer size in szidx'th function argument (in array elements, not necessarily bytes) // Currently we can't tell the compiler that the output will be 0-terminated. -#define __strninout(idx,szidx) __attribute__((nonnull(idx),access(read_write,idx,szidx),null_terminated_string_arg(idx))) +#define __strninout(idx,szidx) __attribute__((nonnull(idx),__access3(read_write,idx,szidx))) // __bufinout: Argument idx (counted left to right from 1) is a non-NULL buffer the function reads and writes, buffer size in szidx'th function argument (in array elements, not necessarily bytes) -#define __bufinout(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_write,bufidx,szidx))) -#elif GCC_VERSION_ATLEAST(10, 0) -#define __strin(idx) __attribute__((nonnull(idx),access(read_only,idx))) -#define __strnin(idx,szidx) __attribute__((nonnull(idx),access(read_only,idx,szidx))) -#define __bufin(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_only,bufidx,szidx))) -#define __strout(idx) __attribute__((nonnull(idx),access(write_only,idx))) -#define __strnout(idx,szidx) __attribute__((nonnull(idx),access(write_only,idx,szidx))) -#define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx),access(write_only,bufidx,szidx))) -#define __strinout(idx) __attribute__((nonnull(idx),access(read_write,idx))) -#define __strninout(idx,szidx) __attribute__((nonnull(idx),access(read_write,idx,szidx))) -#define __bufinout(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_write,bufidx,szidx))) +#define __bufinout(bufidx,szidx) __attribute__((nonnull(bufidx),__access3(read_write,bufidx,szidx))) -#elif GCC_VERSION_ATLEAST(3, 3) - -#define __strin(idx) __attribute__((nonnull(idx))) -#define __strnin(idx,szidx) __attribute__((nonnull(idx))) -#define __bufin(bufidx,szidx) __attribute__((nonnull(bufidx))) -#define __strout(idx) __attribute__((nonnull(idx))) -#define __strnout(idx,szidx) __attribute__((nonnull(idx))) -#define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx))) -#define __strinout(idx) __attribute__((nonnull(idx))) -#define __strninout(idx,szidx) __attribute__((nonnull(idx))) -#define __bufinout(bufidx,szidx) __attribute__((nonnull(bufidx))) - -#endif #endif // !defined(__GNUC__) #endif // !defined(__dietlibc__ +#if __has_attribute(ownership_takes) +#define att_new __attribute__((ownership_returns(malloc))) +#define att_free(idx) __attribute__((ownership_takes(malloc, idx))) +#define att_holds(idx) __attribute__((ownership_holds(malloc, idx))) +#else +#define att_new +#define att_free(idx) +#define att_holds(idx) +#endif + +#if __GNUC__ >= 11 +#define att_free_with(func,argpos) __attribute__((malloc(func,argpos))) +#else +#define att_free_with(func,argpos) __attribute__((malloc)) +#endif + #endif diff --git a/fmt.h b/fmt.h index af81cde..9b07271 100644 --- a/fmt.h +++ b/fmt.h @@ -242,11 +242,11 @@ size_t fmt_pb_double(char* dest,size_t fieldno,double d) noexcept; att_write(1) size_t fmt_pb_float(char* dest,size_t fieldno,float f) noexcept; -att_writen(1,4) +att_write(1) att_readn(3,4) size_t fmt_pb_string(char* dest,size_t fieldno,const char* s,size_t l) noexcept; /* fmt_netstring can return 0 if (src,len) is clearly invalid */ -att_writen(1,3) +att_write(1) att_readn(2,3) size_t fmt_netstring(char* dest,const char* src,size_t len) noexcept; /* Marshaling helper functions. diff --git a/iob.h b/iob.h index 63894da..aba88a8 100644 --- a/iob.h +++ b/iob.h @@ -39,25 +39,44 @@ typedef struct io_batch { /* Initialize an io_batch. Return 0 on success, -1 on malloc failure for * embedded array */ +att_nonnull((1)) +att_warn_unused_result int iob_init(io_batch* b,size_t hint_entries); + +/* iob_reset closes files and frees buffer in the io_batch, and the + * array with the buffer, but not the batch itself (in case it's a local + * variable and not malloced) */ +void iob_reset(io_batch* b); + +/* iob_free does iob_reset but also frees the batch itself */ +void iob_free(io_batch* b); + /* initialize an io_batch that auto-frees entries as soon as * iob_send/iob_write have written them. Return 0 on success, -1 on * malloc failure for embedded array */ +att_nonnull((1)) +att_warn_unused_result int iob_init_autofree(io_batch* b,size_t hint_entries); /* malloc and initialize an io_batch */ +att_free_with(iob_free,1) +att_new io_batch* iob_new(size_t hint_entries); + /* malloc and initialize an io_batch that auto-frees entries as soon as * iob_send/iob_write have written them */ +att_free_with(iob_free,1) io_batch* iob_new_autofree(size_t hint_entries); /* queue buffer in io_batch */ att_readn(2,3) +att_holds(1) int iob_addbuf(io_batch* b,const void* buf,uint64 n); /* queue buffer in io_batch, and give ownership to batch. */ /* the io_batch functions will take care of freeing it. */ att_readn(2,3) +att_free(1) int iob_addbuf_free(io_batch* b,const void* buf,uint64 n); /* queue mmapped memory reagion in io_batch, and give ownership to batch. */ @@ -67,11 +86,13 @@ int iob_addbuf_munmap(io_batch* b,const void* buf,uint64 n); /* queue asciiz string in io_batch. */ att_read(2) +att_holds(2) int iob_adds(io_batch* b,const char* s); /* queue asciiz string in io_batch, and give ownership to batch. */ /* the io_batch functions will take care of freeing it. */ att_read(2) +att_free(2) int iob_adds_free(io_batch* b,const char* s); /* queue file contents in io_batch. */ @@ -93,13 +114,9 @@ int64 iob_write(int64 s,io_batch* b,io_write_callback cb); /* same as iob_write if the TLS library also has a sendfile function */ int64 iob_write2(int64 s,io_batch* b,io_write_callback cb,io_sendfile_callback sfcb); -/* iob_reset closes files and frees buffer in the io_batch, and the - * array with the buffer, but not the batch itself (in case it's a local - * variable and not malloced) */ -void iob_reset(io_batch* b); -/* iob_free does iob_reset but also frees the batch itself */ -void iob_free(io_batch* b); void iob_prefetch(io_batch* b,uint64 bytes); + +att_pure uint64 iob_bytesleft(const io_batch* b); #ifdef __cplusplus