From: Aleksey Kliger (λgeek) Date: Thu, 5 Oct 2017 21:31:11 +0000 (-0400) Subject: Initial set of Ward sgen annotations (#5705) X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=a984f20e232d863a9d3b7848023f78816aa282e7 Initial set of Ward sgen annotations (#5705) * [ward] Expand MONO_PERMIT to empty string when not running Ward See https://github.com/evincarofautumn/Ward#annotating-your-code for the Ward permissions syntax * sgen_gc_locked * sgen_world_stopped * sgen_lock_gc * sgen_stop_world --- diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 4f8a285f499..4fc0e362d4e 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -593,7 +593,7 @@ typedef struct { static EphemeronLinkNode *ephemeron_list; /* LOCKING: requires that the GC lock is held */ -static void +static MONO_PERMIT (need (sgen_gc_locked)) void null_ephemerons_for_domain (MonoDomain *domain) { EphemeronLinkNode *current = ephemeron_list, *prev = NULL; diff --git a/mono/sgen/gc-internal-agnostic.h b/mono/sgen/gc-internal-agnostic.h index fef115796dd..f1c887b5754 100644 --- a/mono/sgen/gc-internal-agnostic.h +++ b/mono/sgen/gc-internal-agnostic.h @@ -14,6 +14,7 @@ #include #include +#include "mono/utils/ward.h" #include "mono/utils/mono-compiler.h" #include "mono/utils/parse.h" #include "mono/utils/memfuncs.h" @@ -82,17 +83,21 @@ typedef void* MonoGCDescriptor; gboolean mono_gc_parse_environment_string_extract_number (const char *str, size_t *out); -MonoGCDescriptor mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size); -MonoGCDescriptor mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size); +MonoGCDescriptor mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size) + MONO_PERMIT (need (sgen_lock_gc)); +MonoGCDescriptor mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size) + MONO_PERMIT (need (sgen_lock_gc)); /* simple interface for data structures needed in the runtime */ -MonoGCDescriptor mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits); +MonoGCDescriptor mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits) + MONO_PERMIT (need (sgen_lock_gc)); /* Return a root descriptor for a vector with repeating refs bitmap */ MonoGCDescriptor mono_gc_make_vector_descr (void); /* Return a root descriptor for a root with all refs */ -MonoGCDescriptor mono_gc_make_root_descr_all_refs (int numbits); +MonoGCDescriptor mono_gc_make_root_descr_all_refs (int numbits) + MONO_PERMIT (need (sgen_lock_gc)); /* Return the bitmap encoded by a descriptor */ gsize* mono_gc_get_bitmap_for_descr (MonoGCDescriptor descr, int *numbits); diff --git a/mono/sgen/sgen-client.h b/mono/sgen/sgen-client.h index 99d77857935..4137cacc3c2 100644 --- a/mono/sgen/sgen-client.h +++ b/mono/sgen/sgen-client.h @@ -69,13 +69,15 @@ void sgen_client_finalize_notify (void); * Returns TRUE if no ephemerons have been marked. Will be called again if it returned * FALSE. If ephemerons are not supported, just return TRUE. */ -gboolean sgen_client_mark_ephemerons (ScanCopyContext ctx); +gboolean sgen_client_mark_ephemerons (ScanCopyContext ctx) + MONO_PERMIT (need (sgen_gc_locked)); /* * Clear ephemeron pairs with unreachable keys. * We pass the copy func so we can figure out if an array was promoted or not. */ -void sgen_client_clear_unreachable_ephemerons (ScanCopyContext ctx); +void sgen_client_clear_unreachable_ephemerons (ScanCopyContext ctx) + MONO_PERMIT (need (sgen_gc_locked)); /* * May return NULL. Must be an aligned pointer. @@ -174,8 +176,10 @@ void sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gbool * Stop and restart the world, i.e., all threads that interact with the managed heap. For * single-threaded programs this is a nop. */ -void sgen_client_stop_world (int generation); -void sgen_client_restart_world (int generation, gint64 *stw_time); +void sgen_client_stop_world (int generation) + MONO_PERMIT (need (sgen_gc_locked)); +void sgen_client_restart_world (int generation, gint64 *stw_time) + MONO_PERMIT (need (sgen_gc_locked)); /* * Must return FALSE. The bridge is not supported outside of Mono. diff --git a/mono/sgen/sgen-fin-weak-hash.c b/mono/sgen/sgen-fin-weak-hash.c index e227281c12d..814b516a272 100644 --- a/mono/sgen/sgen-fin-weak-hash.c +++ b/mono/sgen/sgen-fin-weak-hash.c @@ -229,7 +229,7 @@ sgen_finalize_in_range (int generation, ScanCopyContext ctx) } /* LOCKING: requires that the GC lock is held */ -static void +static MONO_PERMIT (need (sgen_gc_locked)) void register_for_finalization (GCObject *obj, void *user_data, int generation) { SgenHashTable *hash_table = get_finalize_entry_hash_table (generation); @@ -346,7 +346,7 @@ try_lock_stage_for_processing (int num_entries, volatile gint32 *next_entry) } /* LOCKING: requires that the GC lock is held */ -static void +static MONO_PERMIT (need (sgen_gc_locked)) void process_stage_entries (int num_entries, volatile gint32 *next_entry, StageEntry *entries, void (*process_func) (GCObject*, void*, int)) { int i; @@ -528,7 +528,7 @@ add_stage_entry (int num_entries, volatile gint32 *next_entry, StageEntry *entri } /* LOCKING: requires that the GC lock is held */ -static void +static MONO_PERMIT (need (sgen_gc_locked)) void process_fin_stage_entry (GCObject *obj, void *user_data, int index) { if (ptr_in_nursery (obj)) @@ -558,7 +558,7 @@ sgen_object_register_for_finalization (GCObject *obj, void *user_data) } /* LOCKING: requires that the GC lock is held */ -static void +static MONO_PERMIT (need (sgen_gc_locked)) void finalize_with_predicate (SgenObjectPredicateFunc predicate, void *user_data, SgenHashTable *hash_table) { GCObject *object; diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h index 4ed1ec495f9..4c7377e31ee 100644 --- a/mono/sgen/sgen-gc.h +++ b/mono/sgen/sgen-gc.h @@ -31,6 +31,7 @@ typedef struct _SgenThreadInfo SgenThreadInfo; #include "mono/utils/atomic.h" #include "mono/utils/mono-os-mutex.h" #include "mono/utils/mono-coop-mutex.h" +#include "mono/utils/ward.h" #include "mono/sgen/sgen-conf.h" #include "mono/sgen/sgen-hash-table.h" #include "mono/sgen/sgen-protocol.h" @@ -292,7 +293,8 @@ enum { SGEN_GC_BIT_FINALIZER_AWARE = 4, }; -void sgen_gc_init (void); +void sgen_gc_init (void) + MONO_PERMIT (need (sgen_lock_gc)); void sgen_os_init (void); @@ -392,8 +394,10 @@ enum { extern SgenHashTable roots_hash [ROOT_TYPE_NUM]; -int sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, const char *msg); -void sgen_deregister_root (char* addr); +int sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, const char *msg) + MONO_PERMIT (need (sgen_lock_gc)); +void sgen_deregister_root (char* addr) + MONO_PERMIT (need (sgen_lock_gc)); typedef void (*IterateObjectCallbackFunc) (GCObject*, size_t, void*); @@ -797,27 +801,35 @@ void sgen_clear_togglerefs (char *start, char *end, ScanCopyContext ctx); void sgen_process_togglerefs (void); void sgen_register_test_toggleref_callback (void); -void sgen_mark_bridge_object (GCObject *obj); -void sgen_collect_bridge_objects (int generation, ScanCopyContext ctx); +void sgen_mark_bridge_object (GCObject *obj) + MONO_PERMIT (need (sgen_gc_locked)); +void sgen_collect_bridge_objects (int generation, ScanCopyContext ctx) + MONO_PERMIT (need (sgen_gc_locked)); typedef gboolean (*SgenObjectPredicateFunc) (GCObject *obj, void *user_data); -void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track); +void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track) + MONO_PERMIT (need (sgen_gc_locked, sgen_world_stopped)); gboolean sgen_gc_is_object_ready_for_finalization (GCObject *object); -void sgen_gc_lock (void); -void sgen_gc_unlock (void); +void sgen_gc_lock (void) MONO_PERMIT (use (sgen_lock_gc), grant (sgen_gc_locked), revoke (sgen_lock_gc)); +void sgen_gc_unlock (void) MONO_PERMIT (use (sgen_gc_locked), revoke (sgen_gc_locked), grant (sgen_lock_gc)); void sgen_queue_finalization_entry (GCObject *obj); const char* sgen_generation_name (int generation); -void sgen_finalize_in_range (int generation, ScanCopyContext ctx); -void sgen_null_link_in_range (int generation, ScanCopyContext ctx, gboolean track); -void sgen_process_fin_stage_entries (void); +void sgen_finalize_in_range (int generation, ScanCopyContext ctx) + MONO_PERMIT (need (sgen_gc_locked)); +void sgen_null_link_in_range (int generation, ScanCopyContext ctx, gboolean track) + MONO_PERMIT (need (sgen_gc_locked, sgen_world_stopped)); +void sgen_process_fin_stage_entries (void) + MONO_PERMIT (need (sgen_gc_locked)); gboolean sgen_have_pending_finalizers (void); -void sgen_object_register_for_finalization (GCObject *obj, void *user_data); +void sgen_object_register_for_finalization (GCObject *obj, void *user_data) + MONO_PERMIT (need (sgen_lock_gc)); -void sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data); +void sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data) + MONO_PERMIT (need (sgen_lock_gc)); void sgen_remove_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, int generation); void sgen_set_suspend_finalizers (void); @@ -839,19 +851,25 @@ enum { void sgen_pin_object (GCObject *object, SgenGrayQueue *queue); void sgen_set_pinned_from_failed_allocation (mword objsize); -void sgen_ensure_free_space (size_t size, int generation); -void sgen_gc_collect (int generation); -void sgen_perform_collection (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish, gboolean stw); +void sgen_ensure_free_space (size_t size, int generation) + MONO_PERMIT (need (sgen_gc_locked, sgen_stop_world)); +void sgen_gc_collect (int generation) + MONO_PERMIT (need (sgen_lock_gc, sgen_stop_world)); +void sgen_perform_collection (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish, gboolean stw) + MONO_PERMIT (need (sgen_gc_locked, sgen_stop_world)); int sgen_gc_collection_count (int generation); /* FIXME: what exactly does this return? */ -size_t sgen_gc_get_used_size (void); +size_t sgen_gc_get_used_size (void) + MONO_PERMIT (need (sgen_lock_gc)); size_t sgen_gc_get_total_heap_allocation (void); /* STW */ -void sgen_stop_world (int generation); -void sgen_restart_world (int generation); +void sgen_stop_world (int generation) + MONO_PERMIT (need (sgen_gc_locked), use (sgen_stop_world), grant (sgen_world_stopped), revoke (sgen_stop_world)); +void sgen_restart_world (int generation) + MONO_PERMIT (need (sgen_gc_locked), use (sgen_world_stopped), revoke (sgen_world_stopped), grant (sgen_stop_world)); gboolean sgen_is_world_stopped (void); gboolean sgen_set_allow_synchronous_major (gboolean flag); @@ -874,7 +892,8 @@ extern mword los_memory_usage; extern mword los_memory_usage_total; void sgen_los_free_object (LOSObject *obj); -void* sgen_los_alloc_large_inner (GCVTable vtable, size_t size); +void* sgen_los_alloc_large_inner (GCVTable vtable, size_t size) + MONO_PERMIT (need (sgen_gc_locked, sgen_stop_world)); void sgen_los_sweep (void); gboolean sgen_ptr_is_in_los (char *ptr, char **start); void sgen_los_iterate_objects (IterateObjectCallbackFunc cb, void *user_data); @@ -912,7 +931,8 @@ void sgen_nursery_alloc_prepare_for_major (void); GCObject* sgen_alloc_for_promotion (GCObject *obj, size_t objsize, gboolean has_references); -GCObject* sgen_alloc_obj_nolock (GCVTable vtable, size_t size); +GCObject* sgen_alloc_obj_nolock (GCVTable vtable, size_t size) + MONO_PERMIT (need (sgen_gc_locked, sgen_stop_world)); GCObject* sgen_try_alloc_obj_nolock (GCVTable vtable, size_t size); /* Threads */ @@ -958,21 +978,25 @@ sgen_is_object_alive_for_current_gen (GCObject *object) return sgen_major_is_object_alive (object); } -int sgen_gc_invoke_finalizers (void); +int sgen_gc_invoke_finalizers (void) + MONO_PERMIT (need (sgen_lock_gc)); /* GC handles */ void sgen_init_gchandles (void); -void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track); +void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track) + MONO_PERMIT (need (sgen_gc_locked)); typedef gpointer (*SgenGCHandleIterateCallback) (gpointer hidden, GCHandleType handle_type, int max_generation, gpointer user); guint32 sgen_gchandle_new (GCObject *obj, gboolean pinned); guint32 sgen_gchandle_new_weakref (GCObject *obj, gboolean track_resurrection); -void sgen_gchandle_iterate (GCHandleType handle_type, int max_generation, SgenGCHandleIterateCallback callback, gpointer user); +void sgen_gchandle_iterate (GCHandleType handle_type, int max_generation, SgenGCHandleIterateCallback callback, gpointer user) + MONO_PERMIT (need (sgen_world_stopped)); void sgen_gchandle_set_target (guint32 gchandle, GCObject *obj); -void sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_data); +void sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_data) + MONO_PERMIT (need (sgen_world_stopped)); gpointer sgen_gchandle_get_metadata (guint32 gchandle); GCObject *sgen_gchandle_get_target (guint32 gchandle); void sgen_gchandle_free (guint32 gchandle); @@ -1018,9 +1042,12 @@ typedef enum { void sgen_clear_tlabs (void); -GCObject* sgen_alloc_obj (GCVTable vtable, size_t size); -GCObject* sgen_alloc_obj_pinned (GCVTable vtable, size_t size); -GCObject* sgen_alloc_obj_mature (GCVTable vtable, size_t size); +GCObject* sgen_alloc_obj (GCVTable vtable, size_t size) + MONO_PERMIT (need (sgen_lock_gc, sgen_stop_world)); +GCObject* sgen_alloc_obj_pinned (GCVTable vtable, size_t size) + MONO_PERMIT (need (sgen_lock_gc, sgen_stop_world)); +GCObject* sgen_alloc_obj_mature (GCVTable vtable, size_t size) + MONO_PERMIT (need (sgen_lock_gc, sgen_stop_world)); /* Debug support */ @@ -1028,7 +1055,8 @@ void sgen_check_remset_consistency (void); void sgen_check_mod_union_consistency (void); void sgen_check_major_refs (void); void sgen_check_whole_heap (gboolean allow_missing_pinning); -void sgen_check_whole_heap_stw (void); +void sgen_check_whole_heap_stw (void) + MONO_PERMIT (need (sgen_gc_locked, sgen_stop_world)); void sgen_check_objref (char *obj); void sgen_check_heap_marked (gboolean nursery_must_be_pinned); void sgen_check_nursery_objects_pinned (gboolean pinned); diff --git a/mono/utils/Makefile.am b/mono/utils/Makefile.am index 119d7c94c2c..94416bc9537 100644 --- a/mono/utils/Makefile.am +++ b/mono/utils/Makefile.am @@ -180,7 +180,8 @@ monoutils_sources = \ os-event.h \ refcount.h \ w32api.h \ - unlocked.h + unlocked.h \ + ward.h arch_sources = diff --git a/mono/utils/ward.h b/mono/utils/ward.h new file mode 100644 index 00000000000..5d85d350364 --- /dev/null +++ b/mono/utils/ward.h @@ -0,0 +1,20 @@ +#ifndef WARD_H +#define WARD_H + +/* + * Ward is a static analysis tool that can be used to check for the presense of + * a certain class of bugs in C code. + * + * See https://github.com/evincarofautumn/Ward#annotating-your-code for the Ward + * permission annotations syntax. + * + * The Mono permissions are defined in + * https://github.com/evincarofautumn/Ward/blob/prod/mono.config + */ +#if defined(__WARD__) +#define MONO_PERMIT(...) __attribute__ ((ward (__VA_ARGS__))) +#else +#define MONO_PERMIT(...) /*empty*/ +#endif + +#endif