diff options
| author | Daniel Colascione | 2014-04-02 17:18:08 -0700 |
|---|---|---|
| committer | Daniel Colascione | 2014-04-02 17:18:08 -0700 |
| commit | 01ae0fbf30b74e2490144fceabbf5bc5d96f1ba7 (patch) | |
| tree | 59ca8d7de3510d720153f1cc2d368bd145f21f48 | |
| parent | 4fd68bf6cc1dce6c95001fbbac95cef32c86359d (diff) | |
| download | emacs-01ae0fbf30b74e2490144fceabbf5bc5d96f1ba7.tar.gz emacs-01ae0fbf30b74e2490144fceabbf5bc5d96f1ba7.zip | |
Add GC bug investigation code
| -rw-r--r-- | lisp/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/subr.el | 51 | ||||
| -rw-r--r-- | src/ChangeLog | 7 | ||||
| -rw-r--r-- | src/alloc.c | 105 | ||||
| -rw-r--r-- | src/data.c | 5 | ||||
| -rw-r--r-- | src/lisp.h | 3 |
6 files changed, 152 insertions, 25 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f754e5e852b..6c457ba6282 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2014-04-03 Daniel Colascione <dancol@dancol.org> | ||
| 2 | |||
| 3 | * subr.el (set-transient-map): Remove rms's workaround entirely; | ||
| 4 | use new `suspicious-object' subr to mark our lambda for closer | ||
| 5 | scrutiny during gc. | ||
| 6 | |||
| 1 | 2014-04-02 Richard Stallman <rms@gnu.org> | 7 | 2014-04-02 Richard Stallman <rms@gnu.org> |
| 2 | 8 | ||
| 3 | * subr.el (set-transient-map): Comment out previous change. | 9 | * subr.el (set-transient-map): Comment out previous change. |
diff --git a/lisp/subr.el b/lisp/subr.el index 79d90862ed5..5de69d92e33 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -4292,33 +4292,34 @@ lookup sequence then continues." | |||
| 4292 | ;; Don't use letrec, because equal (in add/remove-hook) would get trapped | 4292 | ;; Don't use letrec, because equal (in add/remove-hook) would get trapped |
| 4293 | ;; in a cycle. | 4293 | ;; in a cycle. |
| 4294 | (fset clearfun | 4294 | (fset clearfun |
| 4295 | (lambda () | 4295 | (suspicious-object |
| 4296 | (with-demoted-errors "set-transient-map PCH: %S" | 4296 | (lambda () |
| 4297 | (unless (cond | 4297 | (with-demoted-errors "set-transient-map PCH: %S" |
| 4298 | ((not (eq map (cadr overriding-terminal-local-map))) | 4298 | (unless (cond |
| 4299 | ;; There's presumably some other transient-map in | 4299 | ((not (eq map (cadr overriding-terminal-local-map))) |
| 4300 | ;; effect. Wait for that one to terminate before we | 4300 | ;; There's presumably some other transient-map in |
| 4301 | ;; remove ourselves. | 4301 | ;; effect. Wait for that one to terminate before we |
| 4302 | ;; For example, if isearch and C-u both use transient | 4302 | ;; remove ourselves. |
| 4303 | ;; maps, then the lifetime of the C-u should be nested | 4303 | ;; For example, if isearch and C-u both use transient |
| 4304 | ;; within isearch's, so the pre-command-hook of | 4304 | ;; maps, then the lifetime of the C-u should be nested |
| 4305 | ;; isearch should be suspended during the C-u one so | 4305 | ;; within isearch's, so the pre-command-hook of |
| 4306 | ;; we don't exit isearch just because we hit 1 after | 4306 | ;; isearch should be suspended during the C-u one so |
| 4307 | ;; C-u and that 1 exits isearch whereas it doesn't | 4307 | ;; we don't exit isearch just because we hit 1 after |
| 4308 | ;; exit C-u. | 4308 | ;; C-u and that 1 exits isearch whereas it doesn't |
| 4309 | t) | 4309 | ;; exit C-u. |
| 4310 | ((null keep-pred) nil) | 4310 | t) |
| 4311 | ((eq t keep-pred) | 4311 | ((null keep-pred) nil) |
| 4312 | (eq this-command | 4312 | ((eq t keep-pred) |
| 4313 | (lookup-key map (this-command-keys-vector)))) | 4313 | (eq this-command |
| 4314 | (t (funcall keep-pred))) | 4314 | (lookup-key map (this-command-keys-vector)))) |
| 4315 | (internal-pop-keymap map 'overriding-terminal-local-map) | 4315 | (t (funcall keep-pred))) |
| 4316 | (remove-hook 'pre-command-hook clearfun) | 4316 | (internal-pop-keymap map 'overriding-terminal-local-map) |
| 4317 | (when on-exit (funcall on-exit)) | 4317 | (remove-hook 'pre-command-hook clearfun) |
| 4318 | ;; Comment out the fset if you want to debug the GC bug. | 4318 | (when on-exit (funcall on-exit)) |
| 4319 | ;; Comment out the fset if you want to debug the GC bug. | ||
| 4319 | ;;; (fset clearfun nil) | 4320 | ;;; (fset clearfun nil) |
| 4320 | ;;; (set clearfun nil) | 4321 | ;;; (set clearfun nil) |
| 4321 | )))) | 4322 | ))))) |
| 4322 | (add-hook 'pre-command-hook clearfun) | 4323 | (add-hook 'pre-command-hook clearfun) |
| 4323 | (internal-push-keymap map 'overriding-terminal-local-map))) | 4324 | (internal-push-keymap map 'overriding-terminal-local-map))) |
| 4324 | 4325 | ||
diff --git a/src/ChangeLog b/src/ChangeLog index 22b15a5b00f..1da08defc39 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2014-04-03 Daniel Colascione <dancol@dancol.org> | ||
| 2 | |||
| 3 | * data.c (Ffset): Abort if we're trying to set a function call to | ||
| 4 | a dead lisp object. | ||
| 5 | |||
| 6 | * lisp.h (EARRAYSIZE): New macro. | ||
| 7 | |||
| 1 | 2014-04-02 Martin Rudalics <rudalics@gmx.at> | 8 | 2014-04-02 Martin Rudalics <rudalics@gmx.at> |
| 2 | 9 | ||
| 3 | * xterm.c (x_new_font): Don't calculate non-toolkit scrollbar | 10 | * xterm.c (x_new_font): Don't calculate non-toolkit scrollbar |
diff --git a/src/alloc.c b/src/alloc.c index e5cd5fed4e3..8ec0421e7a4 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -48,6 +48,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 48 | 48 | ||
| 49 | #include <verify.h> | 49 | #include <verify.h> |
| 50 | 50 | ||
| 51 | #ifdef HAVE_EXECINFO_H | ||
| 52 | #include <execinfo.h> /* For backtrace */ | ||
| 53 | #endif | ||
| 54 | |||
| 51 | #if (defined ENABLE_CHECKING \ | 55 | #if (defined ENABLE_CHECKING \ |
| 52 | && defined HAVE_VALGRIND_VALGRIND_H \ | 56 | && defined HAVE_VALGRIND_VALGRIND_H \ |
| 53 | && !defined USE_VALGRIND) | 57 | && !defined USE_VALGRIND) |
| @@ -192,6 +196,36 @@ static ptrdiff_t pure_bytes_used_non_lisp; | |||
| 192 | 196 | ||
| 193 | const char *pending_malloc_warning; | 197 | const char *pending_malloc_warning; |
| 194 | 198 | ||
| 199 | #if 0 /* Normally, pointer sanity only on request... */ | ||
| 200 | #ifdef ENABLE_CHECKING | ||
| 201 | #define SUSPICIOUS_OBJECT_CHECKING 1 | ||
| 202 | #endif | ||
| 203 | #endif | ||
| 204 | |||
| 205 | /* ... but unconditionally use SUSPICIOUS_OBJECT_CHECKING while the GC | ||
| 206 | bug is unresolved. */ | ||
| 207 | #define SUSPICIOUS_OBJECT_CHECKING 1 | ||
| 208 | |||
| 209 | #ifdef SUSPICIOUS_OBJECT_CHECKING | ||
| 210 | struct suspicious_free_record { | ||
| 211 | void* suspicious_object; | ||
| 212 | #ifdef HAVE_EXECINFO_H | ||
| 213 | void* backtrace[128]; | ||
| 214 | #endif | ||
| 215 | }; | ||
| 216 | static void* suspicious_objects[32]; | ||
| 217 | static int suspicious_object_index; | ||
| 218 | struct suspicious_free_record suspicious_free_history[64]; | ||
| 219 | static int suspicious_free_history_index; | ||
| 220 | /* Find the first currently-monitored suspicious pointer in range | ||
| 221 | [begin,end) or NULL if no such pointer exists. */ | ||
| 222 | static void* find_suspicious_object_in_range (void* begin, void* end); | ||
| 223 | static void detect_suspicious_free (void* ptr); | ||
| 224 | #else | ||
| 225 | #define find_suspicious_object_in_range(begin, end) NULL | ||
| 226 | #define detect_suspicious_free(ptr) (void) | ||
| 227 | #endif | ||
| 228 | |||
| 195 | /* Maximum amount of C stack to save when a GC happens. */ | 229 | /* Maximum amount of C stack to save when a GC happens. */ |
| 196 | 230 | ||
| 197 | #ifndef MAX_SAVE_STACK | 231 | #ifndef MAX_SAVE_STACK |
| @@ -2922,6 +2956,7 @@ vector_nbytes (struct Lisp_Vector *v) | |||
| 2922 | static void | 2956 | static void |
| 2923 | cleanup_vector (struct Lisp_Vector *vector) | 2957 | cleanup_vector (struct Lisp_Vector *vector) |
| 2924 | { | 2958 | { |
| 2959 | detect_suspicious_free (vector); | ||
| 2925 | if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FONT) | 2960 | if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FONT) |
| 2926 | && ((vector->header.size & PSEUDOVECTOR_SIZE_MASK) | 2961 | && ((vector->header.size & PSEUDOVECTOR_SIZE_MASK) |
| 2927 | == FONT_OBJECT_MAX)) | 2962 | == FONT_OBJECT_MAX)) |
| @@ -3081,6 +3116,9 @@ allocate_vectorlike (ptrdiff_t len) | |||
| 3081 | mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); | 3116 | mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); |
| 3082 | #endif | 3117 | #endif |
| 3083 | 3118 | ||
| 3119 | if (find_suspicious_object_in_range (p, (char*)p + nbytes)) | ||
| 3120 | emacs_abort (); | ||
| 3121 | |||
| 3084 | consing_since_gc += nbytes; | 3122 | consing_since_gc += nbytes; |
| 3085 | vector_cells_consed += len; | 3123 | vector_cells_consed += len; |
| 3086 | } | 3124 | } |
| @@ -3780,6 +3818,7 @@ refill_memory_reserve (void) | |||
| 3780 | Vmemory_full = Qnil; | 3818 | Vmemory_full = Qnil; |
| 3781 | #endif | 3819 | #endif |
| 3782 | } | 3820 | } |
| 3821 | |||
| 3783 | 3822 | ||
| 3784 | /************************************************************************ | 3823 | /************************************************************************ |
| 3785 | C Stack Marking | 3824 | C Stack Marking |
| @@ -6787,6 +6826,71 @@ which_symbols (Lisp_Object obj, EMACS_INT find_max) | |||
| 6787 | return found; | 6826 | return found; |
| 6788 | } | 6827 | } |
| 6789 | 6828 | ||
| 6829 | #ifdef SUSPICIOUS_OBJECT_CHECKING | ||
| 6830 | |||
| 6831 | static void* | ||
| 6832 | find_suspicious_object_in_range (void* begin, void* end) | ||
| 6833 | { | ||
| 6834 | char* begin_a = begin; | ||
| 6835 | char* end_a = end; | ||
| 6836 | int i; | ||
| 6837 | |||
| 6838 | for (i = 0; i < EARRAYSIZE (suspicious_objects); ++i) { | ||
| 6839 | char* suspicious_object = suspicious_objects[i]; | ||
| 6840 | if (begin_a <= suspicious_object && suspicious_object < end_a) | ||
| 6841 | return suspicious_object; | ||
| 6842 | } | ||
| 6843 | |||
| 6844 | return NULL; | ||
| 6845 | } | ||
| 6846 | |||
| 6847 | static void | ||
| 6848 | detect_suspicious_free (void* ptr) | ||
| 6849 | { | ||
| 6850 | int i; | ||
| 6851 | struct suspicious_free_record* rec; | ||
| 6852 | |||
| 6853 | eassert (ptr != NULL); | ||
| 6854 | |||
| 6855 | for (i = 0; i < EARRAYSIZE (suspicious_objects); ++i) | ||
| 6856 | if (suspicious_objects[i] == ptr) | ||
| 6857 | { | ||
| 6858 | rec = &suspicious_free_history[suspicious_free_history_index++]; | ||
| 6859 | if (suspicious_free_history_index == | ||
| 6860 | EARRAYSIZE (suspicious_free_history)) | ||
| 6861 | { | ||
| 6862 | suspicious_free_history_index = 0; | ||
| 6863 | } | ||
| 6864 | |||
| 6865 | memset (rec, 0, sizeof (rec)); | ||
| 6866 | rec->suspicious_object = ptr; | ||
| 6867 | #ifdef HAVE_EXECINFO_H | ||
| 6868 | backtrace (&rec->backtrace[0], EARRAYSIZE (rec->backtrace)); | ||
| 6869 | #endif | ||
| 6870 | suspicious_objects[i] = NULL; | ||
| 6871 | } | ||
| 6872 | } | ||
| 6873 | |||
| 6874 | #endif /* SUSPICIOUS_OBJECT_CHECKING */ | ||
| 6875 | |||
| 6876 | DEFUN ("suspicious-object", Fsuspicious_object, Ssuspicious_object, 1, 1, 0, | ||
| 6877 | doc: /* Return OBJ, maybe marking it for extra scrutiny. | ||
| 6878 | If Emacs is compiled with suspicous object checking, capture | ||
| 6879 | a stack trace when OBJ is freed in order to help track down | ||
| 6880 | garbage collection bugs. Otherwise, do nothing and return OBJ. */) | ||
| 6881 | (Lisp_Object obj) | ||
| 6882 | { | ||
| 6883 | #ifdef SUSPICIOUS_OBJECT_CHECKING | ||
| 6884 | /* Right now, we care only about vectors. */ | ||
| 6885 | if (VECTORLIKEP (obj)) { | ||
| 6886 | suspicious_objects[suspicious_object_index++] = XVECTOR (obj); | ||
| 6887 | if (suspicious_object_index == EARRAYSIZE (suspicious_objects)) | ||
| 6888 | suspicious_object_index = 0; | ||
| 6889 | } | ||
| 6890 | #endif | ||
| 6891 | return obj; | ||
| 6892 | } | ||
| 6893 | |||
| 6790 | #ifdef ENABLE_CHECKING | 6894 | #ifdef ENABLE_CHECKING |
| 6791 | 6895 | ||
| 6792 | bool suppress_checking; | 6896 | bool suppress_checking; |
| @@ -6957,6 +7061,7 @@ The time is in seconds as a floating point value. */); | |||
| 6957 | defsubr (&Sgarbage_collect); | 7061 | defsubr (&Sgarbage_collect); |
| 6958 | defsubr (&Smemory_limit); | 7062 | defsubr (&Smemory_limit); |
| 6959 | defsubr (&Smemory_use_counts); | 7063 | defsubr (&Smemory_use_counts); |
| 7064 | defsubr (&Ssuspicious_object); | ||
| 6960 | 7065 | ||
| 6961 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES | 7066 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES |
| 6962 | defsubr (&Sgc_status); | 7067 | defsubr (&Sgc_status); |
diff --git a/src/data.c b/src/data.c index 4ef81f2474e..dd220987fd7 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -727,6 +727,11 @@ DEFUN ("fset", Ffset, Sfset, 2, 2, 0, | |||
| 727 | if (AUTOLOADP (function)) | 727 | if (AUTOLOADP (function)) |
| 728 | Fput (symbol, Qautoload, XCDR (function)); | 728 | Fput (symbol, Qautoload, XCDR (function)); |
| 729 | 729 | ||
| 730 | /* Convert to eassert or remove after GC bug is found. In the | ||
| 731 | meantime, check unconditionally, at a slight perf hit. */ | ||
| 732 | if (valid_lisp_object_p (definition) < 1) | ||
| 733 | emacs_abort (); | ||
| 734 | |||
| 730 | set_symbol_function (symbol, definition); | 735 | set_symbol_function (symbol, definition); |
| 731 | 736 | ||
| 732 | return definition; | 737 | return definition; |
diff --git a/src/lisp.h b/src/lisp.h index f8b5384ceb0..b8c909ab60d 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -58,6 +58,9 @@ INLINE_HEADER_BEGIN | |||
| 58 | #define max(a, b) ((a) > (b) ? (a) : (b)) | 58 | #define max(a, b) ((a) > (b) ? (a) : (b)) |
| 59 | #define min(a, b) ((a) < (b) ? (a) : (b)) | 59 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
| 60 | 60 | ||
| 61 | /* Find number of elements in array */ | ||
| 62 | #define EARRAYSIZE(arr) (sizeof (arr) / sizeof ((arr)[0])) | ||
| 63 | |||
| 61 | /* EMACS_INT - signed integer wide enough to hold an Emacs value | 64 | /* EMACS_INT - signed integer wide enough to hold an Emacs value |
| 62 | EMACS_INT_MAX - maximum value of EMACS_INT; can be used in #if | 65 | EMACS_INT_MAX - maximum value of EMACS_INT; can be used in #if |
| 63 | pI - printf length modifier for EMACS_INT | 66 | pI - printf length modifier for EMACS_INT |