summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSverker Eriksson <sverker@erlang.org>2022-05-03 18:52:05 +0200
committerGitHub <noreply@github.com>2022-05-03 18:52:05 +0200
commit71b0d4e7cfe121a06d104593d8c56f4ff26b5276 (patch)
tree8a367a410cf0b71574016f52452b946b783174ea
parent09df89ad0bfab6ab1c3e20aac77ca8c70b84bb08 (diff)
parentb9ded1603bd6c3fbab63cac642f87b71cf10fc6a (diff)
downloaderlang-71b0d4e7cfe121a06d104593d8c56f4ff26b5276.tar.gz
Merge PR-5932 from sverker/erts/alloc-function-attribute/OTP-18006
Add function attributes in erl_nif & erl_driver API
-rw-r--r--erts/emulator/beam/erl_alloc.h10
-rw-r--r--erts/emulator/beam/erl_db.h11
-rw-r--r--erts/emulator/beam/erl_driver.h20
-rw-r--r--erts/emulator/beam/erl_drv_nif.h54
-rw-r--r--erts/emulator/beam/erl_message.h24
-rw-r--r--erts/emulator/beam/erl_nif.h10
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h18
-rw-r--r--erts/emulator/beam/erl_process.h4
-rw-r--r--erts/emulator/beam/erl_utils.h2
-rw-r--r--erts/emulator/beam/sys.h56
10 files changed, 157 insertions, 52 deletions
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index d0282e8f2f..00ab6284d7 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -213,11 +213,11 @@ Eterm erts_alloc_set_dyn_param(struct process*, Eterm);
#if !ERTS_ALC_DO_INLINE
-void *erts_alloc(ErtsAlcType_t type, Uint size);
-void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size);
void erts_free(ErtsAlcType_t type, void *ptr);
-void *erts_alloc_fnf(ErtsAlcType_t type, Uint size);
-void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size);
+void *erts_alloc(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_USD(2,erts_free,2);
+void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size) ERTS_ATTR_ALLOC_SIZE(3);
+void *erts_alloc_fnf(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_USD(2,erts_free,2);
+void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size) ERTS_ATTR_ALLOC_SIZE(3);
int erts_is_allctr_wrapper_prelocked(void);
#ifdef ERTS_HAVE_IS_IN_LITERAL_RANGE
int erts_is_in_literal_range(void* ptr);
@@ -227,7 +227,7 @@ int erts_get_thr_alloc_ix(void);
#endif /* #if !ERTS_ALC_DO_INLINE */
-void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size);
+void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_US(2);
#ifndef ERTS_CACHE_LINE_SIZE
/* Assumed cache line size */
diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h
index 81eeab1781..34b9b871be 100644
--- a/erts/emulator/beam/erl_db.h
+++ b/erts/emulator/beam/erl_db.h
@@ -173,12 +173,15 @@ do { \
ERTS_GLB_INLINE void *erts_db_alloc(ErtsAlcType_t type,
DbTable *tab,
- Uint size);
+ Uint size) ERTS_ATTR_MALLOC_US(3);
ERTS_GLB_INLINE void *erts_db_alloc_fnf(ErtsAlcType_t type,
DbTable *tab,
- Uint size);
-ERTS_GLB_INLINE void *erts_db_alloc_nt(ErtsAlcType_t type, Uint size);
-ERTS_GLB_INLINE void *erts_db_alloc_fnf_nt(ErtsAlcType_t type, Uint size);
+ Uint size) ERTS_ATTR_MALLOC_US(3);
+ERTS_GLB_INLINE void*
+erts_db_alloc_nt(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_US(2);
+
+ERTS_GLB_INLINE void*
+erts_db_alloc_fnf_nt(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_US(2);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h
index 7fc6670ff0..25469de7cc 100644
--- a/erts/emulator/beam/erl_driver.h
+++ b/erts/emulator/beam/erl_driver.h
@@ -404,9 +404,11 @@ EXTERN int get_port_flags(ErlDrvPort port);
* since the binary is a shared object it MUST be written once.
*/
-EXTERN ErlDrvBinary* driver_alloc_binary(ErlDrvSizeT size);
-EXTERN ErlDrvBinary* driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size);
EXTERN void driver_free_binary(ErlDrvBinary *bin);
+EXTERN ErlDrvBinary* driver_alloc_binary(ErlDrvSizeT size)
+ ERL_NAPI_ATTR_MALLOC_UD(driver_free_binary,1);
+EXTERN ErlDrvBinary* driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size)
+ ERL_NAPI_ATTR_WUR;
/* Reference count on driver binaries */
EXTERN ErlDrvSInt driver_binary_get_refc(ErlDrvBinary *dbp);
@@ -414,9 +416,11 @@ EXTERN ErlDrvSInt driver_binary_inc_refc(ErlDrvBinary *dbp);
EXTERN ErlDrvSInt driver_binary_dec_refc(ErlDrvBinary *dbp);
/* Allocation interface */
-EXTERN void *driver_alloc(ErlDrvSizeT size);
-EXTERN void *driver_realloc(void *ptr, ErlDrvSizeT size);
EXTERN void driver_free(void *ptr);
+EXTERN void *driver_alloc(ErlDrvSizeT size)
+ ERL_NAPI_ATTR_MALLOC_USD(1, driver_free, 1);
+EXTERN void *driver_realloc(void *ptr, ErlDrvSizeT size)
+ ERL_NAPI_ATTR_ALLOC_SIZE(2);
/* Queue interface */
EXTERN int driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len);
@@ -448,18 +452,18 @@ EXTERN void driver_system_info(ErlDrvSysInfo *sip, size_t si_size);
* erl driver thread functions.
*/
-EXTERN ErlDrvMutex *erl_drv_mutex_create(char *name);
EXTERN void erl_drv_mutex_destroy(ErlDrvMutex *mtx);
+EXTERN ErlDrvMutex *erl_drv_mutex_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_mutex_destroy,1);
EXTERN int erl_drv_mutex_trylock(ErlDrvMutex *mtx);
EXTERN void erl_drv_mutex_lock(ErlDrvMutex *mtx);
EXTERN void erl_drv_mutex_unlock(ErlDrvMutex *mtx);
-EXTERN ErlDrvCond *erl_drv_cond_create(char *name);
EXTERN void erl_drv_cond_destroy(ErlDrvCond *cnd);
+EXTERN ErlDrvCond *erl_drv_cond_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_cond_destroy,1);
EXTERN void erl_drv_cond_signal(ErlDrvCond *cnd);
EXTERN void erl_drv_cond_broadcast(ErlDrvCond *cnd);
EXTERN void erl_drv_cond_wait(ErlDrvCond *cnd, ErlDrvMutex *mtx);
-EXTERN ErlDrvRWLock *erl_drv_rwlock_create(char *name);
EXTERN void erl_drv_rwlock_destroy(ErlDrvRWLock *rwlck);
+EXTERN ErlDrvRWLock *erl_drv_rwlock_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_rwlock_destroy,1);
EXTERN int erl_drv_rwlock_tryrlock(ErlDrvRWLock *rwlck);
EXTERN void erl_drv_rwlock_rlock(ErlDrvRWLock *rwlck);
EXTERN void erl_drv_rwlock_runlock(ErlDrvRWLock *rwlck);
@@ -470,8 +474,8 @@ EXTERN int erl_drv_tsd_key_create(char *name, ErlDrvTSDKey *key);
EXTERN void erl_drv_tsd_key_destroy(ErlDrvTSDKey key);
EXTERN void erl_drv_tsd_set(ErlDrvTSDKey key, void *data);
EXTERN void *erl_drv_tsd_get(ErlDrvTSDKey key);
-EXTERN ErlDrvThreadOpts *erl_drv_thread_opts_create(char *name);
EXTERN void erl_drv_thread_opts_destroy(ErlDrvThreadOpts *opts);
+EXTERN ErlDrvThreadOpts *erl_drv_thread_opts_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_thread_opts_destroy,1);
EXTERN int erl_drv_thread_create(char *name,
ErlDrvTid *tid,
void * (*func)(void *),
diff --git a/erts/emulator/beam/erl_drv_nif.h b/erts/emulator/beam/erl_drv_nif.h
index 53d1a3a531..ee27953f7f 100644
--- a/erts/emulator/beam/erl_drv_nif.h
+++ b/erts/emulator/beam/erl_drv_nif.h
@@ -168,4 +168,58 @@ typedef struct {
# endif
#endif
+#define ERL_NAPI_ATTR_WUR
+#define ERL_NAPI_ATTR_ALLOC_SIZE(SZPOS)
+#define ERL_NAPI_ATTR_MALLOC_U
+#define ERL_NAPI_ATTR_MALLOC_US(SZPOS)
+#define ERL_NAPI_ATTR_MALLOC_UD(DTOR, PTRPOS)
+#define ERL_NAPI_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS)
+#define ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS)
+
+/* ERL_NAPI_ATTR_MALLOC_xxx:
+ * U: Returns pointer to Undefined data. ((malloc))
+ * S: Has Size argument with nr of bytes of returned data. ((alloc_size(SZPOS)))
+ * D: Has 1-to-1 Deallocator function with ptr argument. ((malloc(DTOR,PTRPOS)))
+ */
+
+#ifdef __has_attribute
+# if __has_attribute(warn_unused_result)
+# undef ERL_NAPI_ATTR_WUR
+# define ERL_NAPI_ATTR_WUR __attribute__((warn_unused_result))
+# endif
+# if __has_attribute(alloc_size)
+# undef ERL_NAPI_ATTR_ALLOC_SIZE
+# define ERL_NAPI_ATTR_ALLOC_SIZE(SZPOS) \
+ __attribute__((alloc_size(SZPOS))) ERL_NAPI_ATTR_WUR
+# endif
+# if __has_attribute(malloc)
+# undef ERL_NAPI_ATTR_MALLOC_U
+# define ERL_NAPI_ATTR_MALLOC_U __attribute__((malloc)) ERL_NAPI_ATTR_WUR
+
+# undef ERL_NAPI_ATTR_MALLOC_US
+# define ERL_NAPI_ATTR_MALLOC_US(SZPOS) \
+ __attribute__((malloc)) ERL_NAPI_ATTR_ALLOC_SIZE(SZPOS)
+
+# undef ERL_NAPI_ATTR_MALLOC_D
+# if defined(__GNUC__) && __GNUC__ >= 11
+# define ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS) \
+ __attribute__((malloc(DTOR,PTRPOS))) \
+ ERL_NAPI_ATTR_WUR
+# else
+# define ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS) \
+ ERL_NAPI_ATTR_WUR
+# endif
+
+# undef ERL_NAPI_ATTR_MALLOC_UD
+# define ERL_NAPI_ATTR_MALLOC_UD(DTOR, PTRPOS) \
+ ERL_NAPI_ATTR_MALLOC_U \
+ ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS)
+
+# undef ERL_NAPI_ATTR_MALLOC_USD
+# define ERL_NAPI_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS) \
+ ERL_NAPI_ATTR_MALLOC_US(SZPOS) \
+ ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS)
+# endif
+#endif
+
#endif /* __ERL_DRV_NIF_H__ */
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index 76a7964ab8..218b3b6df8 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -514,30 +514,8 @@ Eterm erts_change_message_queue_management(Process *c_p, Eterm new_state);
void erts_cleanup_messages(ErtsMessage *mp);
-void *erts_alloc_message_ref(void);
void erts_free_message_ref(void *);
-
-#define ERTS_SMALL_FIX_MSG_SZ 10
-#define ERTS_MEDIUM_FIX_MSG_SZ 20
-#define ERTS_LARGE_FIX_MSG_SZ 30
-
-void *erts_alloc_small_message(void);
-void erts_free_small_message(void *mp);
-
-typedef struct {
- ErtsMessage m;
- Eterm data[ERTS_SMALL_FIX_MSG_SZ-1];
-} ErtsSmallFixSzMessage;
-
-typedef struct {
- ErtsMessage m;
- Eterm data[ERTS_MEDIUM_FIX_MSG_SZ-1];
-} ErtsMediumFixSzMessage;
-
-typedef struct {
- ErtsMessage m;
- Eterm data[ERTS_LARGE_FIX_MSG_SZ-1];
-} ErtsLargeFixSzMessage;
+void *erts_alloc_message_ref(void) ERTS_ATTR_MALLOC_D(erts_free_message_ref,1);
ErtsMessage *erts_try_alloc_message_on_heap(Process *pp,
erts_aint32_t *psp,
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index b2984eac0c..a9a81483f6 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -346,6 +346,16 @@ extern TWinDynNifCallbacks WinDynNifCallbacks;
#else /* non windows or included from emulator itself */
+/* Redundant declaration of deallocator functions as they are referred to by
+ * __attribute__(malloc) of allocator functions and we cannot change
+ * the declaration order in erl_nif_api_funcs.h due to Windows. */
+extern void enif_free(void* ptr);
+extern void enif_mutex_destroy(ErlNifMutex *mtx);
+extern void enif_cond_destroy(ErlNifCond *cnd);
+extern void enif_rwlock_destroy(ErlNifRWLock *rwlck);
+extern void enif_thread_opts_destroy(ErlNifThreadOpts *opts);
+extern void enif_ioq_destroy(ErlNifIOQueue *q);
+
# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) extern RET_TYPE NAME ARGS
# include "erl_nif_api_funcs.h"
# undef ERL_NIF_API_FUNC_DECL
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 27fa953099..05ad83dfdd 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -31,7 +31,7 @@
*/
#ifdef ERL_NIF_API_FUNC_DECL
ERL_NIF_API_FUNC_DECL(void*,enif_priv_data,(ErlNifEnv*));
-ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(size_t size));
+ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(size_t size) ERL_NAPI_ATTR_MALLOC_USD(1,enif_free,1));
ERL_NIF_API_FUNC_DECL(void,enif_free,(void* ptr));
ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term));
@@ -60,17 +60,17 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string, ErlNifCharEncoding));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env));
-ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name));
+ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_mutex_destroy,1));
ERL_NIF_API_FUNC_DECL(void,enif_mutex_destroy,(ErlNifMutex *mtx));
ERL_NIF_API_FUNC_DECL(int,enif_mutex_trylock,(ErlNifMutex *mtx));
ERL_NIF_API_FUNC_DECL(void,enif_mutex_lock,(ErlNifMutex *mtx));
ERL_NIF_API_FUNC_DECL(void,enif_mutex_unlock,(ErlNifMutex *mtx));
-ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name));
+ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_cond_destroy,1));
ERL_NIF_API_FUNC_DECL(void,enif_cond_destroy,(ErlNifCond *cnd));
ERL_NIF_API_FUNC_DECL(void,enif_cond_signal,(ErlNifCond *cnd));
ERL_NIF_API_FUNC_DECL(void,enif_cond_broadcast,(ErlNifCond *cnd));
ERL_NIF_API_FUNC_DECL(void,enif_cond_wait,(ErlNifCond *cnd, ErlNifMutex *mtx));
-ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name));
+ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_rwlock_destroy,1));
ERL_NIF_API_FUNC_DECL(void,enif_rwlock_destroy,(ErlNifRWLock *rwlck));
ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrlock,(ErlNifRWLock *rwlck));
ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rlock,(ErlNifRWLock *rwlck));
@@ -82,7 +82,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_tsd_key_create,(char *name, ErlNifTSDKey *key));
ERL_NIF_API_FUNC_DECL(void,enif_tsd_key_destroy,(ErlNifTSDKey key));
ERL_NIF_API_FUNC_DECL(void,enif_tsd_set,(ErlNifTSDKey key, void *data));
ERL_NIF_API_FUNC_DECL(void*,enif_tsd_get,(ErlNifTSDKey key));
-ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name));
+ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_thread_opts_destroy,1));
ERL_NIF_API_FUNC_DECL(void,enif_thread_opts_destroy,(ErlNifThreadOpts *opts));
ERL_NIF_API_FUNC_DECL(int,enif_thread_create,(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts));
ERL_NIF_API_FUNC_DECL(ErlNifTid,enif_thread_self,(void));
@@ -90,7 +90,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_equal_tids,(ErlNifTid tid1, ErlNifTid tid2));
ERL_NIF_API_FUNC_DECL(void,enif_thread_exit,(void *resp));
ERL_NIF_API_FUNC_DECL(int,enif_thread_join,(ErlNifTid, void **respp));
-ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(void* ptr, size_t size));
+ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(void* ptr, size_t size) ERL_NAPI_ATTR_ALLOC_SIZE(2));
ERL_NIF_API_FUNC_DECL(void,enif_system_info,(ErlNifSysInfo *sip, size_t si_size));
ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(FILE* filep, const char *format, ...));
ERL_NIF_API_FUNC_DECL(int,enif_inspect_iolist_as_binary,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifBinary* bin));
@@ -108,7 +108,7 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple_from_array,(ErlNifEnv*, const
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt));
ERL_NIF_API_FUNC_DECL(int,enif_is_empty_list,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(ErlNifResourceType*,enif_open_resource_type,(ErlNifEnv*, const char* module_str, const char* name_str, void (*dtor)(ErlNifEnv*,void *), ErlNifResourceFlags flags, ErlNifResourceFlags* tried));
-ERL_NIF_API_FUNC_DECL(void*,enif_alloc_resource,(ErlNifResourceType* type, size_t size));
+ERL_NIF_API_FUNC_DECL(void *, enif_alloc_resource, (ErlNifResourceType *type, size_t size) ERL_NAPI_ATTR_MALLOC_US(2));
ERL_NIF_API_FUNC_DECL(void,enif_release_resource,(void* obj));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource,(ErlNifEnv*, void* obj));
ERL_NIF_API_FUNC_DECL(int,enif_get_resource,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp));
@@ -121,7 +121,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_get_list_length,(ErlNifEnv* env, ERL_NIF_TERM ter
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_atom_len,(ErlNifEnv* env, const char* name, size_t len));
ERL_NIF_API_FUNC_DECL(int, enif_make_existing_atom_len,(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom, ErlNifCharEncoding));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding));
-ERL_NIF_API_FUNC_DECL(ErlNifEnv*,enif_alloc_env,(void));
+ERL_NIF_API_FUNC_DECL(ErlNifEnv*,enif_alloc_env,(void) ERL_NAPI_ATTR_WUR);
ERL_NIF_API_FUNC_DECL(void,enif_free_env,(ErlNifEnv* env));
ERL_NIF_API_FUNC_DECL(void,enif_clear_env,(ErlNifEnv* env));
ERL_NIF_API_FUNC_DECL(int,enif_send,(ErlNifEnv* env, const ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg));
@@ -184,7 +184,7 @@ ERL_NIF_API_FUNC_DECL(ErlNifUInt64,enif_hash,(ErlNifHash type, ERL_NIF_TERM term
ERL_NIF_API_FUNC_DECL(int, enif_whereis_pid, (ErlNifEnv *env, ERL_NIF_TERM name, ErlNifPid *pid));
ERL_NIF_API_FUNC_DECL(int, enif_whereis_port, (ErlNifEnv *env, ERL_NIF_TERM name, ErlNifPort *port));
-ERL_NIF_API_FUNC_DECL(ErlNifIOQueue *,enif_ioq_create,(ErlNifIOQueueOpts opts));
+ERL_NIF_API_FUNC_DECL(ErlNifIOQueue *,enif_ioq_create,(ErlNifIOQueueOpts opts) ERL_NAPI_ATTR_MALLOC_D(enif_ioq_destroy,1));
ERL_NIF_API_FUNC_DECL(void,enif_ioq_destroy,(ErlNifIOQueue *q));
ERL_NIF_API_FUNC_DECL(int,enif_ioq_enq_binary,(ErlNifIOQueue *q, ErlNifBinary *bin, size_t skip));
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index bc06334df3..1883a851ba 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1746,9 +1746,9 @@ Uint64 erts_get_proc_interval(void);
Uint64 erts_ensure_later_proc_interval(Uint64);
Uint64 erts_step_proc_interval(void);
-ErtsProcList *erts_proclist_create(Process *);
-ErtsProcList *erts_proclist_copy(ErtsProcList *);
void erts_proclist_destroy(ErtsProcList *);
+ErtsProcList *erts_proclist_create(Process *) ERTS_ATTR_MALLOC_D(erts_proclist_destroy,1);
+ErtsProcList *erts_proclist_copy(ErtsProcList *);
void erts_proclist_dump(fmtfn_t to, void *to_arg, ErtsProcList*);
ERTS_GLB_INLINE int erts_proclist_same(ErtsProcList *, Process *);
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index ae2fb646a1..e83881f52f 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -108,8 +108,8 @@ void erts_init_utils(void);
void erts_init_utils_mem(void);
void erts_utils_sched_spec_data_init(void);
-erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint);
void erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *);
+erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint) ERTS_ATTR_MALLOC_D(erts_destroy_tmp_dsbuf,1);
int eq(Eterm, Eterm);
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index fca4e02ab1..20b0571e43 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -1373,4 +1373,60 @@ erts_raw_env_next_char(byte *p, int encoding)
#define ERTS_SPAWN_DRV_CONTROL_MAGIC_NUMBER 0x04c76a00U
#define ERTS_FORKER_DRV_CONTROL_MAGIC_NUMBER 0x050a7800U
+#define ERTS_ATTR_WUR
+#define ERTS_ATTR_ALLOC_SIZE(SZPOS)
+#define ERTS_ATTR_MALLOC_U
+#define ERTS_ATTR_MALLOC_US(SZPOS)
+#define ERTS_ATTR_MALLOC_UD(DTOR, PTRPOS)
+#define ERTS_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS)
+#define ERTS_ATTR_MALLOC_D(DTOR, PTRPOS)
+
+/* ERTS_ATTR_MALLOC_xxx:
+ * U: Returns pointer to Undefined data. ((malloc))
+ * S: Has Size argument with nr of bytes of returned data. ((alloc_size(SZPOS)))
+ * D: Has 1-to-1 Deallocator function with ptr argument. ((malloc(DTOR,PTRPOS)))
+ * (D does not work on INLINE functions)
+ */
+
+#ifdef __has_attribute
+# if __has_attribute(warn_unused_result)
+# undef ERTS_ATTR_WUR
+# define ERTS_ATTR_WUR __attribute__((warn_unused_result))
+# endif
+# if __has_attribute(alloc_size)
+# undef ERTS_ATTR_ALLOC_SIZE
+# define ERTS_ATTR_ALLOC_SIZE(SZPOS) __attribute__((alloc_size(SZPOS)))
+# endif
+# if __has_attribute(malloc)
+# undef ERTS_ATTR_MALLOC_U
+# define ERTS_ATTR_MALLOC_U __attribute__((malloc)) ERTS_ATTR_WUR
+
+# undef ERTS_ATTR_MALLOC_US
+# define ERTS_ATTR_MALLOC_US(SZPOS) \
+ __attribute__((malloc)) \
+ ERTS_ATTR_ALLOC_SIZE(SZPOS) \
+ ERTS_ATTR_WUR
+
+# undef ERTS_ATTR_MALLOC_D
+# if defined(__GNUC__) && __GNUC__ >= 11
+# define ERTS_ATTR_MALLOC_D(DTOR, PTRPOS) \
+ __attribute__((malloc(DTOR,PTRPOS))) \
+ ERTS_ATTR_WUR
+# else
+# define ERTS_ATTR_MALLOC_D(DTOR, PTRPOS) \
+ ERTS_ATTR_WUR
+# endif
+
+# undef ERTS_ATTR_MALLOC_UD
+# define ERTS_ATTR_MALLOC_UD(DTOR, PTRPOS) \
+ ERTS_ATTR_MALLOC_U \
+ ERTS_ATTR_MALLOC_D(DTOR, PTRPOS)
+
+# undef ERTS_ATTR_MALLOC_USD
+# define ERTS_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS) \
+ ERTS_ATTR_MALLOC_US(SZPOS) \
+ ERTS_ATTR_MALLOC_D(DTOR, PTRPOS)
+# endif
#endif
+
+#endif /* __SYS_H__ */