Repository: spyder-ide/spyder

Issue:
Force-stop does not work on hanged progress.
## Description

**What steps will reproduce the problem?**

1. Have a hanged process (memory overflow). Hitting "stop" button and "Ctrl+C"/"Ctrl+Z" does not work..
2. Try closing the console + terminate kernel
3. Got it.

**What is the expected output? What do you see instead?**


**Please provide any additional information below**

  File "C:\ProgramData\Anaconda3\envs\py3conda\lib\site-packages\spyder\plugins\ipythonconsole.py", line 1235, in close_client
    self.filenames.pop(index)
IndexError: pop index out of range


## Version and main components

* Spyder Version: 3.2.0 
* Python Version: 3.6.1
* Qt Versions: 5.6.2, PyQt5 5.6 on Windows

## Dependencies
```
pyflakes >=0.6.0 :  1.5.0 (OK)
pycodestyle >=2.3:  2.3.1 (OK)
pygments >=2.0   :  2.2.0 (OK)
pandas >=0.13.1  :  0.20.1 (OK)
numpy >=1.7      :  1.12.1 (OK)
sphinx >=0.6.6   :  1.5.6 (OK)
rope >=0.9.4     :  0.9.4-1 (OK)
jedi >=0.9.0     :  0.10.2 (OK)
nbconvert >=4.0  :  5.1.1 (OK)
sympy >=0.7.3    :  1.0 (OK)
cython >=0.21    :  0.25.2 (OK)
qtconsole >=4.2.0:  4.3.0 (OK)
IPython >=4.0    :  5.3.0 (OK)
pylint >=0.25    :  1.6.4 (OK)

```



Discussion:
So do you get this error after closing a hanged console?
Yes. I just realized I forgot one thing. Before terminating the hanged console, I opened a new console (and another one sharing the same kernel as the new console) just to see whether Spyder itself was hanged. The error first popped up when I tried to terminate the newly created consoles, and popped up again when I tried to terminate the hanged console.
@dalthviz, please take a look at this one.

To have the equivalent of a hanged console, you can run this code on it

```python
while True:
    1
```

Resolving patch:
diff --git a/spyder/plugins/ipythonconsole.py b/spyder/plugins/ipythonconsole.py
--- a/spyder/plugins/ipythonconsole.py
+++ b/spyder/plugins/ipythonconsole.py
@@ -1252,10 +1252,20 @@ def close_client(self, index=None, client=None, force=False):
         # Note: client index may have changed after closing related widgets
         self.tabwidget.removeTab(self.tabwidget.indexOf(client))
         self.clients.remove(client)
-        self.filenames.pop(index)
+
+        # This is needed to prevent that hanged consoles make reference
+        # to an index that doesn't exist. See issue 4881
+        try:
+            self.filenames.pop(index)
+        except IndexError:
+            pass
+
+        self.update_tabs_text()
+
+        # Create a new client if the console is about to become empty
         if not self.tabwidget.count() and self.create_new_client_if_empty:
             self.create_new_client()
-        self.update_tabs_text()
+
         self.update_plugin_title.emit()
 
     def get_client_index_from_id(self, client_id):
@@ -1451,12 +1461,18 @@ def disambiguate_fname(self, fname):
 
     def update_tabs_text(self):
         """Update the text from the tabs."""
-        for index, fname in enumerate(self.filenames):
-            client = self.clients[index]
-            if fname:
-                self.rename_client_tab(client, self.disambiguate_fname(fname))
-            else:
-                self.rename_client_tab(client, None)
+        # This is needed to prevent that hanged consoles make reference
+        # to an index that doesn't exist. See issue 4881
+        try:
+            for index, fname in enumerate(self.filenames):
+                client = self.clients[index]
+                if fname:
+                    self.rename_client_tab(client,
+                                           self.disambiguate_fname(fname))
+                else:
+                    self.rename_client_tab(client, None)
+        except IndexError:
+            pass
 
     def rename_client_tab(self, client, given_name):
         """Rename client's tab"""


Test patch: