[elinks-dev] Crash when download ends

Kalle Olavi Niemitalo kon at iki.fi
Tue Sep 30 00:33:56 PDT 2008


Please test these patches for 0.11.5.GIT and 0.12pre2.GIT.
(The latter should also apply to 0.13.GIT, except there's a
conflict in NEWS.)

Actually I think we should add this to Bugzilla too,
and update the commit messages and NEWS entry accordingly.

-------------- next part --------------
Fix crash when download ends.

ELinks attempted to display a message box on file_download.term, but
it had already closed that terminal and freed the struct terminal.  To
fix this, reset file_download.term pointers to NULL when the terminal
is about to be destroyed.  Also, assert in download_data_store() that
file_download.term is either NULL or in the global "terminals" list.

Reported by ???? ????????.

---
commit b85c8a744ef7f6d75fca302afe01dc9dac65b4fe
tree 0ed2ce4704e7e8c9eb7a30afc0a43d5aadc30f54
parent 983419b6060bd97e372019c2bdfde32ad2157661
author Kalle Olavi Niemitalo <kon at iki.fi> Tue, 30 Sep 2008 10:06:20 +0300
committer Kalle Olavi Niemitalo <Kalle at Astalo.kon.iki.fi> Tue, 30 Sep 2008 10:12:09 +0300

 NEWS                    |    8 ++++++++
 src/session/download.c  |   27 +++++++++++++++++++++++++++
 src/session/download.h  |    1 +
 src/terminal/terminal.c |   16 ++++++++++++++++
 src/terminal/terminal.h |    6 ++++++
 5 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index 87e6590..5ac4fdd 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,14 @@ You can see the complete list of recent changes, bugfixes and new features
 in the http://repo.or.cz/w/elinks.git[gitweb interface]. See the ChangeLog
 file for details.
 
+ELinks 0.11.5.GIT now:
+----------------------
+
+To be released as 0.11.6.
+
+* critical: fix crash if a download finishes after ELinks has closed
+  the terminal from which the download was started.
+
 ELinks 0.11.5:
 --------------
 
diff --git a/src/session/download.c b/src/session/download.c
index a34a6f8..10e5e8c 100644
--- a/src/session/download.c
+++ b/src/session/download.c
@@ -220,6 +220,29 @@ destroy_downloads(struct session *ses)
 	}
 }
 
+void
+detach_downloads_from_terminal(struct terminal *term)
+{
+	struct file_download *file_download, *next;
+
+	assert(term != NULL);
+	if_assert_failed return;
+
+	foreachsafe (file_download, next, downloads) {
+		if (file_download->term != term)
+			continue;
+
+		if (!file_download->external_handler) {
+			file_download->term = NULL;
+			if (file_download->ses
+			    && file_download->ses->tab->term == term)
+				file_download->ses = NULL;
+			continue;
+		}
+
+		abort_download(file_download);
+	}
+}
 
 static void
 download_error_dialog(struct file_download *file_download, int saved_errno)
@@ -307,6 +330,10 @@ download_data_store(struct download *download, struct file_download *file_downlo
 {
 	struct terminal *term = file_download->term;
 
+	if (term) {
+		assert_terminal_is_in_list(term);
+		if_assert_failed term = file_download->term = NULL;
+	}
 	if (!term) {
 		/* No term here, so no beep. --Zas */
 		abort_download(file_download);
diff --git a/src/session/download.h b/src/session/download.h
index 1bcc4aa..b27cd3b 100644
--- a/src/session/download.h
+++ b/src/session/download.h
@@ -107,6 +107,7 @@ void create_download_file(struct terminal *, unsigned char *, unsigned char **,
 
 void abort_all_downloads(void);
 void destroy_downloads(struct session *);
+void detach_downloads_from_terminal(struct terminal *);
 
 int setup_download_handler(struct session *, struct download *, struct cache_entry *, int);
 
diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index 895e898..3943951 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -115,6 +115,7 @@ destroy_terminal(struct terminal *term)
 #ifdef CONFIG_BOOKMARKS
 	bookmark_auto_save_tabs(term);
 #endif
+	detach_downloads_from_terminal(term);
 
 	while (!list_empty(term->windows))
 		delete_window(term->windows.next);
@@ -197,6 +198,21 @@ unblock_terminal(struct terminal *term)
 		textarea_edit(1, NULL, NULL, NULL, NULL);
 }
 
+#ifndef CONFIG_FASTMEM
+void
+assert_terminal_is_in_list(const struct terminal *suspect)
+{
+	struct terminal *term;
+
+	foreach (term, terminals) {
+		if (term == suspect)
+			return;
+	}
+
+	assertm(0, "Dangling pointer to struct terminal");
+}
+#endif /* !CONFIG_FASTMEM */
+
 void
 exec_on_terminal(struct terminal *term, unsigned char *path,
 		 unsigned char *delete, int fg)
diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h
index 0689f09..c4633d0 100644
--- a/src/terminal/terminal.h
+++ b/src/terminal/terminal.h
@@ -150,6 +150,12 @@ void destroy_all_terminals(void);
 void exec_thread(unsigned char *, int);
 void close_handle(void *);
 
+#ifdef CONFIG_FASTMEM
+#define assert_terminal_is_in_list(term) ((void) 0)
+#else  /* assert() does something */
+void assert_terminal_is_in_list(const struct terminal *term);
+#endif
+
 #define TERM_FN_TITLE	1
 #define TERM_FN_RESIZE	2
 
-------------- next part --------------
Fix crash when download ends.

ELinks attempted to display a message box on file_download.term, but
it had already closed that terminal and freed the struct terminal.  To
fix this, reset file_download.term pointers to NULL when the terminal
is about to be destroyed.  Also, assert in download_data_store() that
file_download.term is either NULL or in the global "terminals" list.

Reported by ???? ????????.
(cherry picked from commit b85c8a744ef7f6d75fca302afe01dc9dac65b4fe)

---
commit d498732a959a5b8ef95840c36b7d4788c008592d
tree 2e19a9a8b7dfa651bfe459418429ed18e7049ecc
parent 6ee45c710a32615742664e5edab436b016df75d2
author Kalle Olavi Niemitalo <kon at iki.fi> Tue, 30 Sep 2008 10:06:20 +0300
committer Kalle Olavi Niemitalo <Kalle at Astalo.kon.iki.fi> Tue, 30 Sep 2008 10:25:49 +0300

 NEWS                    |   17 +++++++++++++----
 src/session/download.c  |   27 +++++++++++++++++++++++++++
 src/session/download.h  |    1 +
 src/terminal/terminal.c |   15 +++++++++++++++
 src/terminal/terminal.h |    6 ++++++
 5 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/NEWS b/NEWS
index 3375d7d..57625d0 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,8 @@ file for details.
 ELinks 0.12pre2.GIT now:
 ------------------------
 
-To be released as 0.12pre3, 0.12rc1, or even 0.12.0.
+To be released as 0.12pre3, 0.12rc1, or even 0.12.0.  This branch also
+includes the changes listed under ``ELinks 0.11.5.GIT'' below.
 
 * Perl scripts can use modules that dynamically load C libraries, like
   XML::LibXML::SAX does.
@@ -17,7 +18,7 @@ ELinks 0.12pre2:
 ----------------
 
 Released on 2008-09-21.  This release also included the changes listed
-under "ELinks 0.11.5" below.
+under ``ELinks 0.11.5'' below.
 
 * bug 954, enhancement 952: Keep track of ECMAScript form and input
   objects instead of constructing new ones on every access.  When the
@@ -73,8 +74,8 @@ Bugs that should be removed from NEWS before the 0.12.0 release:
 ELinks 0.12pre1:
 ----------------
 
-Released on 2008-07-01.  This release also included all the bug fixes
-of ELinks 0.11.4, but not the ones made in 0.11.4.GIT.
+Released on 2008-07-01.  This release also included the changes listed
+under ``ELinks 0.11.4'' below.
 
 Notable new features:
 
@@ -227,6 +228,14 @@ Changes in the experimental SGML/DOM implementation:
 * enhancement: incremental parsing
 * and more.
 
+ELinks 0.11.5.GIT now:
+----------------------
+
+To be released as 0.11.6.
+
+* critical: fix crash if a download finishes after ELinks has closed
+  the terminal from which the download was started.
+
 ELinks 0.11.5:
 --------------
 
diff --git a/src/session/download.c b/src/session/download.c
index e8c76b6..58d9061 100644
--- a/src/session/download.c
+++ b/src/session/download.c
@@ -219,6 +219,29 @@ destroy_downloads(struct session *ses)
 	}
 }
 
+void
+detach_downloads_from_terminal(struct terminal *term)
+{
+	struct file_download *file_download, *next;
+
+	assert(term != NULL);
+	if_assert_failed return;
+
+	foreachsafe (file_download, next, downloads) {
+		if (file_download->term != term)
+			continue;
+
+		if (!file_download->external_handler) {
+			file_download->term = NULL;
+			if (file_download->ses
+			    && file_download->ses->tab->term == term)
+				file_download->ses = NULL;
+			continue;
+		}
+
+		abort_download(file_download);
+	}
+}
 
 static void
 download_error_dialog(struct file_download *file_download, int saved_errno)
@@ -306,6 +329,10 @@ download_data_store(struct download *download, struct file_download *file_downlo
 {
 	struct terminal *term = file_download->term;
 
+	if (term) {
+		assert_terminal_is_in_list(term);
+		if_assert_failed term = file_download->term = NULL;
+	}
 	if (!term) {
 		/* No term here, so no beep. --Zas */
 		abort_download(file_download);
diff --git a/src/session/download.h b/src/session/download.h
index a2b198d..c3aacce 100644
--- a/src/session/download.h
+++ b/src/session/download.h
@@ -108,6 +108,7 @@ void create_download_file(struct terminal *, unsigned char *, unsigned char **,
 
 void abort_all_downloads(void);
 void destroy_downloads(struct session *);
+void detach_downloads_from_terminal(struct terminal *);
 
 int setup_download_handler(struct session *, struct download *, struct cache_entry *, int);
 
diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index 5217cc6..688c930 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -118,6 +118,7 @@ destroy_terminal(struct terminal *term)
 #ifdef CONFIG_BOOKMARKS
 	bookmark_auto_save_tabs(term);
 #endif
+	detach_downloads_from_terminal(term);
 
 	/* delete_window doesn't update term->current_tab, but it
 	   calls redraw_terminal, which requires term->current_tab
@@ -206,6 +207,20 @@ unblock_terminal(struct terminal *term)
 		textarea_edit(1, NULL, NULL, NULL, NULL);
 }
 
+#ifndef CONFIG_FASTMEM
+void
+assert_terminal_is_in_list(const struct terminal *suspect)
+{
+	struct terminal *term;
+
+	foreach (term, terminals) {
+		if (term == suspect)
+			return;
+	}
+
+	assertm(0, "Dangling pointer to struct terminal");
+}
+#endif /* !CONFIG_FASTMEM */
 
 static void
 exec_on_master_terminal(struct terminal *term,
diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h
index b87ac2c..74690d1 100644
--- a/src/terminal/terminal.h
+++ b/src/terminal/terminal.h
@@ -178,6 +178,12 @@ void destroy_all_terminals(void);
 void exec_thread(unsigned char *, int);
 void close_handle(void *);
 
+#ifdef CONFIG_FASTMEM
+#define assert_terminal_is_in_list(term) ((void) 0)
+#else  /* assert() does something */
+void assert_terminal_is_in_list(const struct terminal *term);
+#endif
+
 /** Operations that can be requested with do_terminal_function().
  * The interlink protocol passes these values as one byte in a
  * null-terminated string, so zero cannot be used.  */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 188 bytes
Desc: not available
URL: <http://lists.linuxfromscratch.org/pipermail/elinks-dev/attachments/20080930/59c53569/attachment.sig>


More information about the elinks-dev mailing list