#4116 Infinite search&replace if searching for pipes (|) in regexps (matching empty text)

Next_Major_Version
closed
nobody
None
9
2013-02-24
2012-12-22
Philippe Verdy
No

Open any text file and try searching for pipes (|). This character is common when editing Wikimedia pages or templates externally.

IF by accident you've forgotten to move back to the normal plain text mode and the search field contains "||" or starts by a "|", then this regexp will mean searching for EMPTY strings.

The search & replace will then run in an infinite loop and you'll have NO other option than killing Notepad++, loosing your last unsaved edits.

The regexp may not be used to find EMPTY text, or if it does then for each occurence if must NOT start at the current position in the text, but MOST only return an empty selection starting at the NEXT character. Otherwise it will infinitely return the same EMPTY selection at the current edit position. And if you search and replace, it will infinitely try to append the replacement text.

The simplest fix should NOT return empty selections (even if this is what the regexp means, including searching for "$" in a regexp, which will infinitely match an EMPTY text at end of the current line)

Discussion

  • Philippe Verdy
    Philippe Verdy
    2012-12-22

    Note : the fatal infinite loop occurs if you click "Search&Replace All". It does not occur if you just Search&replace the next occurence (at least there, you can Undo the replacement if this is not what was intended).

    The main cause of this accident is that we can forget to switch from Regexp mode to plain-text mode in the Search&Replace dialog.

     
  • Philippe Verdy
    Philippe Verdy
    2012-12-22

    A more correct fix would be that the Regexp engine memorize the last selection (or position) before starting, and then if it finds an empty selection, it should just skip the match and continue scanning (trying other alternatives). Then if it matches again the same selection of position (and the selection was not modified by a replacement), then it should ignore the match and advance 1 character foreward.

    Beware also of some other replacements with regexps, that don't effectively advance in the search area after the current selection (e.g. search&replace operations that are swapping two fields: they may be swapped infinitely if the replacement text appends some more text that will become the next match).

    In all cases, if something goes wrong in borderline cases, the "Search&Replace All" dialog should continue to listen for a "STOP" button : if it is clicked, then it should position a flag that will be tested continuouly by the regexp engine after performing EACH replacement.

    So PLEASE add a STOP button: it should not necessarily close the dialog, but at least we'll see an intermedisate state of what is happening in the background, showing what is in the last replacement performed). If this turns out to be really a lengthy operation but it is not wrong by itself, we can continue by pressing the "Replace All" button again in the dialog, or we can close it and execute an UNDO operation, without loosing our current edits.

    Note also that the UNDO buffer should be large enough to store ALL operations performed by a click on the button "Replace All". If memory is lacking, stop the replace all operation and display an alert saying that the operations will not be undoable if we continue. This alert should offer us the option to save a backup of the text in the state that was effective before starting the Search&Replace operation, or it could perform this backup automatically (to remove that old text from memory), including in the backup all the history of edits that could be UNDONE before the replacements. This will even give us the possibility of restoring an edited text several steps backward with several UNDO operations.

     
  • Philippe Verdy
    Philippe Verdy
    2012-12-22

    In order to implement a STOP button, and being able to listen it, this means that the "Replace All" button should perform its job in a new thread, so that the current GUI thread remains active to set the "STOP" flag that the new thread will check after each replacement.

    But because the GUI thread will remain active while the Search&Replace operation is running, this also means that the background window will have its text modified while trying to display or update it : beware that in this cases there may be a lot of window refreshes which will make the Search&Replace very slow, or that could not perform a correct display if the text is modified while the window repaint is looking at a text which is constantly changing.

    This means that you'll need also to activate an excluvive lock when a repaint is started (to block temporarily all concurrent modifications of the edit buffer), and the same exclusive lock when the background thread performs each replacement (to block temporarily any repaint that may occur). Otherwise the display may be corrupted or may become unstable or could also hang : normally a repaint operation operates on a text which is not being modified for performing the complete repaint operation of the dirty area.

    The background thread that runs the search and replacements will terminate when it completes its task (no more match found), or when it detects after each replacement that the STOP flag has been set by the GUI thread. At this time, it will set a DONE flag that the GUI thread will be also checking while listening the STOP button, allowing the GUI thread to reenable the Search&Replace dialog in an editable state with (instead of being readonly as soon as we click the "Replace All" button and the new Search&Replace thread is not DONE).
    Then in parallel, the background Search&Replace thread will terminate, and the GUI thread will be able to catch this thread termination.

     
    Last edit: Philippe Verdy 2012-12-22
  • Philippe Verdy
    Philippe Verdy
    2012-12-22

    Another possible improvement : if the GUI thread is currently waiting for either the completion of the Search&Replace thread, or the user clicking the STOP button, it should be able to also suspend the Search&Replace thread temporarily after 30 seconds to display a dialog saying "The Search&Replace operation is unusually long, do you really want to continue?", focusing the user to press either the STOP or CONTINUE button. IF the user presses CONTINUE, no other alert will be displayed, and the Search&Replace thread will be resumed.

    But if the user presses the STOP button in this alert, it will have the same effect as if he pressed the "Stop" button in the Search&Replace dialog (the "Stop" button is displayed in the "Search&Replace dialog" instead of the "Replace All" button, while this dialog is turned in read-only mode to start the Search&Replace background thread, with all other buttons grayed and inactive, and the "close dialog" button having no effect as long as the dialog is in read-only mode and the background search&replace thread is running and not stopped).

     
  • Don HO
    Don HO
    2013-01-02

    • status: open --> accepted
    • milestone: 1.x --> Next_Major_Version
    • priority: 5 --> 9
     
  • Don HO
    Don HO
    2013-02-24

    • status: accepted --> closed