By default, Bugzilla does not search the list of RESOLVED bugs.
You can force it to do so by putting the upper-case word ALL in front of your search query, e.g.: ALL tdelibs
We recommend searching for bugs this way, as you may discover that your bug has already been resolved and fixed in a later release.
Bug 2264 - [Regression] tdefilereplace hangs and does not finish when replacing with multiple lines
Summary: [Regression] tdefilereplace hangs and does not finish when replacing with mul...
Status: RESOLVED FIXED
Alias: None
Product: TDE
Classification: Unclassified
Component: tdeutils (show other bugs)
Version: R14.0.0 [Trinity]
Hardware: Other Linux
: P5 normal
Assignee: Michele Calgaro
URL:
Depends on:
Blocks: R14.0.1 R14.1.0
  Show dependency treegraph
 
Reported: 2014-12-18 11:30 CST by Darrell
Modified: 2015-08-27 10:49 CDT (History)
3 users (show)

See Also:
Compiler Version:
TDE Version String:
Application Version:
Application Name:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Darrell 2014-12-18 11:30:52 CST
Seems to work okay when replacing one line with one line. Replacing one line with two or more lines does not work and this used to work fine.
Comment 1 Michele Calgaro 2015-01-29 18:54:26 CST
Darrell, can you reproduce this bug systematically? If so, can you run tdefilereplace in gdb and when it hangs press Ctrl+C, then thread apply all bt and post the result here?
Does the problem happens on any file or only with specific ones?
Comment 2 Darrell 2015-01-29 19:33:51 CST
When I filed the report I could reproduce the hang every time. I haven't tried since.

I need reminding how to use gdb:

gdb --arg tdefilereplace --nofork

Then what?
Comment 3 Michele Calgaro 2015-01-29 19:41:04 CST
Please be sure to have debug symbols installed before beginning.

1) gdb tdefilereplace --nofork
2) press 'r' to run the program, wait until the main window opens.
3) try to reproduce the problem as you have done before
4) when tdefilereplace hangs, switch to the gdb console, press Ctrl+C to interrupt the process. You should get the gdb prompt
5) type 'thread apply all bt', this will list the stack frames of all available threads
6) post the output here
Comment 4 Darrell 2015-01-29 20:08:10 CST
=========================================================
(gdb) thread apply all bt

Thread 1 (Thread 0xb62b4740 (LWP 28150)):
#0  0xb66b8c1f in __getdents64 () from /lib/libc.so.6
#1  0xb66b8f8a in readdir64_r@@GLIBC_2.2 () from /lib/libc.so.6
#2  0xb6f3f1fa in TQDir::readDirEntries (this=0xbfffd390, nameFilter=..., filterSpec=267, sortSpec=16)
    at tools/qdir_unix.cpp:245
#3  0xb6f51945 in TQDir::entryList (this=this@entry=0xbfffd390, nameFilter=..., filterSpec=267, filterSpec@entry=-1,
    sortSpec=16, sortSpec@entry=-1) at tools/qdir.cpp:846
#4  0xb6007c47 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:983
#5  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#6  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#7  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#8  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#9  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#10 0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#11 0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810a9d8, directoryName=...,
    filesNumber=@0xbfffd9ec: 141) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#12 0xb600cb13 in TDEFileReplacePart::slotReplacingOperation (this=0x810a9d8)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:199
#13 0xb600dad5 in TDEFileReplacePart::slotQuickStringsAdd (this=this@entry=0x810a9d8)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:318
#14 0xb600e046 in TDEFileReplacePart::launchNewProjectDialog (this=this@entry=0x810a9d8, startURL=...)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1612
#15 0xb600e14e in TDEFileReplacePart::slotSetNewParameters (this=this@entry=0x810a9d8)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:100
#16 0xb600e634 in TDEFileReplacePart::tqt_invoke (this=0x810a9d8, _id=5, _o=0xbfffde34)
    at /dev/shm/tdeutils.build/tdefilereplace/tdefilereplacepart.moc:149
#17 0xb6caf342 in TQObject::activate_signal (this=0x81932a0, clist=0x8194348, o=0xbfffde34) at kernel/qobject.cpp:2805
#18 0xb6caf065 in TQObject::activate_signal (this=this@entry=0x81932a0, signal=2) at kernel/qobject.cpp:2746
#19 0xb78a9577 in TDEAction::activated (this=this@entry=0x81932a0) at /dev/shm/tdelibs.build/tdeui/tdeaction.moc:185
#20 0xb78a9938 in TDEAction::slotActivated (this=0x81932a0) at /dev/shm/tdelibs/tdeui/tdeaction.cpp:1118
#21 0xb78a9751 in TDEAction::slotButtonClicked (this=this@entry=0x81932a0, state=TQt::LeftButton)
    at /dev/shm/tdelibs/tdeui/tdeaction.cpp:1163
#22 0xb78acb70 in TDEAction::tqt_invoke (this=0x81932a0, _id=17, _o=0xbfffdfb8)
    at /dev/shm/tdelibs.build/tdeui/tdeaction.moc:230
#23 0xb6caf342 in TQObject::activate_signal (this=this@entry=0x81ecb58, clist=clist@entry=0x81f09d8,
    o=o@entry=0xbfffdfb8) at kernel/qobject.cpp:2805
---Type <return> to continue, or q <return> to quit---  
=========================================================

I did not set maxdepth. Thus the full search path is quite deep and several GBs in size. That said, I do know that in the past this same type of Search/Replace did work.

I again tried with maxdepth=3. Same hang. Backtrace:

=========================================================
(gdb) thread apply all bt

Thread 1 (Thread 0xb62b4740 (LWP 4998)):
#0  0xb66e9b3d in __old__lxstat64 () from /lib/libc.so.6
#1  0xb6653803 in realpath@@GLIBC_2.3 () from /lib/libc.so.6
#2  0xb6f3e74a in TQDir::canonicalPath (this=0xbfffd390) at tools/qdir_unix.cpp:96
#3  0xb6007e9e in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:998
#4  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#5  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#6  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#7  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#8  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#9  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#10 0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
#11 0xb600cb13 in TDEFileReplacePart::slotReplacingOperation (this=0x810aa00)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:199
#12 0xb600dad5 in TDEFileReplacePart::slotQuickStringsAdd (this=this@entry=0x810aa00)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:318
#13 0xb600e046 in TDEFileReplacePart::launchNewProjectDialog (this=this@entry=0x810aa00, startURL=...)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1612
#14 0xb600e14e in TDEFileReplacePart::slotSetNewParameters (this=this@entry=0x810aa00)
    at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:100
#15 0xb600e634 in TDEFileReplacePart::tqt_invoke (this=0x810aa00, _id=5, _o=0xbfffde34)
    at /dev/shm/tdeutils.build/tdefilereplace/tdefilereplacepart.moc:149
#16 0xb6caf342 in TQObject::activate_signal (this=0x8193550, clist=0x81945b8, o=0xbfffde34) at kernel/qobject.cpp:2805
#17 0xb6caf065 in TQObject::activate_signal (this=this@entry=0x8193550, signal=2) at kernel/qobject.cpp:2746
#18 0xb78a9577 in TDEAction::activated (this=this@entry=0x8193550) at /dev/shm/tdelibs.build/tdeui/tdeaction.moc:185
#19 0xb78a9938 in TDEAction::slotActivated (this=0x8193550) at /dev/shm/tdelibs/tdeui/tdeaction.cpp:1118
#20 0xb78a9751 in TDEAction::slotButtonClicked (this=this@entry=0x8193550, state=TQt::LeftButton)
    at /dev/shm/tdelibs/tdeui/tdeaction.cpp:1163
#21 0xb78acb70 in TDEAction::tqt_invoke (this=0x8193550, _id=17, _o=0xbfffdfb8)
    at /dev/shm/tdelibs.build/tdeui/tdeaction.moc:230
#22 0xb6caf342 in TQObject::activate_signal (this=this@entry=0x81ee6f0, clist=clist@entry=0x81f0bd8,
    o=o@entry=0xbfffdfb8) at kernel/qobject.cpp:2805
#23 0xb7966311 in TDEToolBarButton::buttonClicked (this=this@entry=0x81ee6f0, t0=-2, t1=TQt::LeftButton)
    at /dev/shm/tdelibs.build/tdeui/tdetoolbarbutton.moc:164
#24 0xb79684e0 in TDEToolBarButton::mouseReleaseEvent (this=0x81ee6f0, e=0xbfffe3a8)
---Type <return> to continue, or q <return> to quit--- 
=========================================================

Despite the hang, the Search/Replace did seem to actually complete.

When I change focus from tdefilereplace to another app and then return to tdefilereplace, the entire app window is blank, typical of a hung app.
Comment 5 Michele Calgaro 2015-01-29 20:31:06 CST
Thanks. Again in gdb, can you enter frame 4, 5 ,6 (or any that says filesNumber=@0xbfffd9ec:  at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006
using:
f <frame number>
then type:
set p pr
p filePath.ascii()
p fileName.ascii()
and report the output?

If seems the recursion always happens at the same file number, so either there is a circular link in the file system or a non-immediately-evidnet bug in the code.
Comment 6 Michele Calgaro 2015-01-29 20:31:32 CST
Please try at least 3 different frames ;-)
Comment 7 Darrell 2015-01-29 22:39:04 CST
I haven't yet tried capturing frame information.

By the way, yes, the Search and Replace widgets sorely need a history. Running these tests is frustrating.

In this test case, the search path includes a subdirectory that is 6.3 GB. That is the reason I long ago requested the maxdepth option: to bypass large subdirectories as much as possible.

I did a quick test of copying to a temporary location all directories except the 6.3 GB subdirectory. The Search/Replace completed in about 3 seconds, which is about what I expect.

That prompted me to wonder whether tdefilereplace was actually stalling, but instead the 6.3 GB subdirectory is just huge. I ran that search again and waited with a stop watch. The search actually completed after 3 minutes. A long time that easily creates the illusion of a stall.

Next I set maxdepth=1. To my understanding, at that depth the search should complete almost before I start the stop watch. Yet after 4 minutes I had to kill the app as the search had not yet completed. Either maxdepth is not working or I am not using correctly.

In my original problem description I mentioned the "stall" did not happen when I searched and replaced one-liners. I again tested that with maxdepth not set. Same long result so at this point I think my original statement might be a red herring. I do not remember my original search parameters that led me to write that.

Summary:

1. Maxdepth is not working.

2. The illusion of stalling could be avoided by improving the progress feedback. The upper window updates when successful replacements are found, the status bar "Scanned files" result updates when the filtered criteria is satisfied, and the "imitation LEDs at the bottom left of the status bar change color. Those all are positive feedback results. There otherwise is no negative progress feedback --- that is, when no files are being found. That creates the illusion of stalling. Perhaps an easy solution is the status bar could indicate the number of directories searched. Something like:

ooo  Scanned directories: XXX  Scanned files: YYY

3. The fact that I can switch app windows and when returning to tdefilereplace the app window is blank is not good either. That indicates the app is not refreshing itself during the searching except when there is positive feedback. A status bar update of "Scanned directories" would force the window to continually refresh and avoid the blank window bug.

4. In the event of large directories, the user should have some method to interrupt the search. Pressing Esc should be the obvious keyboard option, yet as a GUI app, there also should be a GUI control to interrupt searches.
Comment 8 Michele Calgaro 2015-01-29 23:05:53 CST
I had a quick look (busy with other things today): there is actually some more code for the max depth option to work. The maxDepth is working when searching, but I discovered that it is not implemented when replacing. I thought the search process in both cases was the same, but I see in the code that is is going through two different functions, thus the lack of functionality when trying replacing.

Anyhow looking at the stack frames you posted, you can see continuous recursion on the same folder/file, for example:

#6  0xb6007fa7 in TDEFileReplacePart::recursiveFileReplace (this=0x810aa00, directoryName=...,
    filesNumber=@0xbfffd9ec: 142) at /dev/shm/tdeutils/tdefilereplace/tdefilereplacepart.cpp:1006

that is why I thought there may be a recursive link and asked you to had a look at those frames.

Having said all that, I agrees with your points in the previous comment
Comment 9 Darrell 2015-01-29 23:11:11 CST
I don't know whether this is related, but starting tdefilereplace from a terminal (no gdb) results in the following error:

TQObject::connect: No such slot TDEFileReplaceView::executed(TQListViewItem*)
TQObject::connect:  (sender name:   'm_lvResults')
TQObject::connect:  (receiver name: 'view')
Comment 10 Michele Calgaro 2015-01-29 23:36:20 CST
>TQObject::connect: No such slot TDEFileReplaceView::executed(TQListViewItem*)
>TQObject::connect:  (sender name:   'm_lvResults')
>TQObject::connect:  (receiver name: 'view')

Actually not, this was introduced by changes in bug 2322, which I have now reopened
Comment 11 Darrell 2015-01-29 23:41:54 CST
Okay. I am going to wait until you resolve bugs 2322 and 1238. Resolving the other items will be nice, but one thing at a time.
Comment 12 Darrell 2015-01-30 08:01:23 CST
I suppose now that maxdepth is functional and we since have discovered that there is actually no stalling but just a very long wait, that this bug is no longer valid or resolved.

That still leaves 1) a need for improved status bar feedback when nothing "obvious" is happening and 2) keyboard/mouse methods to allow users to interrupt the searching. Resolve those here or file new bug reports?

Either way, if your continue hacking tdefilereplae I'd rather see history support in the Search and Replace widgets before proceeding with the others. Just too much work to keep repopulating those widgets. Having history support will allow testing other improvements more palatable.
Comment 13 Michele Calgaro 2015-01-30 20:46:15 CST
>That still leaves 1) a need for improved status bar feedback when nothing 
>"obvious" is happening and 2) keyboard/mouse methods to allow users to 
>interrupt the searching. Resolve those here or file new bug reports?

I am not so sure this bug is fully solved, or better based on the stack frames above, I think you have a circular reference in that big folder. In such case TDEFileReplace should still hangs if the maxDepth option is not used.
When searching or replacing, the status bar should display an increasing number of file scanned and the stop button on the toolbar should stop the search. What do you see when searching/replacing without maxDepth? Does the counter keep increasing or not? Does the stop button works or not? I suspect the counter does not increase and the stop button does nothing. We need a fix for:

1) unresponsive GUI with circular references, if my theory is confirmed
2) detect circular references and display a user message. This could be done if we detect too many recursion levels (say >=512)

I know it is a little bit of a hassle, but could you check those frames as required in comment 5 and 6? That would be important for point 1). Thanks.
Comment 14 Darrell 2015-01-31 14:22:45 CST
>What do you see when searching/replacing without maxDepth?
Unless there is a successful replacement, there is no feedback of any kind. When there is a successful replacement, the counter increments and the upper pane updates with the name of the file being added to the list.

>Does the counter keep increasing or not?
The counter increments only when there is a successful replacement. Even when a file is found that satisfies the filter criteria, the counter updates only if there is a successful replacement in the file. I know this because I have 197 *.SlackBuild scripts in the search directory and I see only 142 hits in the counter. Otherwise there is no feedback to help users know the search is continuing. Adding to the status bar the name of the directory being searched would help. The continual status bar updating will also eliminate the entire app window from going blank when the user toggles to a different app window and back.

>Does the stop button works or not?
I am unable to access toolbar buttons and menu options during a search. I suggested adding such an option, yet as I know realize the toolbar and menu already support a Stop function, the real problem seems to be the inability to access those options during a search. The toolbar and menu are disabled/ghosted during a search. I don't think that is preferred behavior. We need to learn why that happens.

I manually searched my local Trinity repo (you can do similarly) for sym links. There are many and I found two dangling/broken sym links. I doubt those broken sym links are part of the problem. I do not know of a way to search for circular links.

I am no longer convinced there is a problem with stalling. A 6.3 GB directory will indeed take a long time to search and I did not understand fully what was happening when I filed the report. Updating the status bar to continually change with the directory being searched will provide much needed visual feedback and will help avoid future bug reports.

From my perspective I see two bugs: 1) not being able to manually stop and 2) no visual feedback with deep searches. Oh, and the Search and Replace text box widgets not having a built-in history. :)

>could you check those frames
Okay.
Comment 15 Darrell 2015-01-31 20:01:24 CST
After running the 'frame <num>' sequence several times I see that the steps are supposed to reveal a file name and path. Each subsequent 'f <num>' request shortens the file path to the parent level. Thus, actually only the first frame is needed as that first frame is the only one that provides the full name and path.

After repeating the sequence several times and interrupting tdefilereplace at arbitrarily different time intervals, I notice the various questionable frames always revealed a different file. If there was an actual circular reference somewhere I would think I would see the same file each time.

Each time I looked at each file and saw nothing obvious. Just plain files. I even saw files listed that were not in the 6.3 GB directory, which now eliminates something peculiar in the 6.3 GB directory.

Further complicating the exercise is tdefilereplace does not actually stall. Just takes about 3 minutes to complete. If I wait for about 3 minutes then the search completes and there is nothing to backtrace. Without a true stall I wonder whether the exercise would ever reveal anything.

Yes tdefilereplace is unresponsive but only in the sense that the menu and toolbar do not work during a search. Yet tdefilereplace is not stalling. Only access to the menu and toolbar is broken.

I am inclined to ignore the gdb frame messages. Instead 1) improve the status bar to provide better feedback, 2) focus on why the menu and toolbar are untouchable during a search and, 3) add history to the Search and Replace widgets.
Comment 16 Michele Calgaro 2015-02-01 17:45:24 CST
> The counter increments only when there is a successful replacement.

Darrell, thanks for all the feedback. 
I see a very different behavior on my system, whether I am only searching, searching & replacing in simulation mode or searching & replacing for real. In all cases, the status bar displays a progressive counter of "scanned files". Stop button in the toolbar and stop command in the menu work as expected and stop the search immediately.

What options are you using for the search? And what are your general options?
Also, when the stop button is disabled, what LED is lit in the bottom left side of the status bar?
Comment 17 Michele Calgaro 2015-02-01 18:06:21 CST
> I am inclined to ignore the gdb frame messages.
I have set up a folder circular reference and with the "follow symbolic link" option enabled and no max depth limit, I can reproduce the "non responsive GUI" problem, followed by a segmentation fault once TDEFileReplace runs out of stack space. 
This is what I was expecting after having seen you stack frames and the TDEFileReplace code. Will work on fixing it next.
Comment 18 Michele Calgaro 2015-02-01 19:09:35 CST
Commit d739846 fixes the unresponsive GUI and application crash described in comment 17.
Comment 19 Michele Calgaro 2015-02-01 19:58:38 CST
Commit c9fa04f adds a 'scanned folder' field in the status bar.
Comment 20 Michele Calgaro 2015-02-01 20:02:31 CST
Darrell, please test the new version on your system and let me know if it looks better. If so, I will close this bug.
Adding history to the search widgets has already been filed as bug 2334.
Comment 21 Michele Calgaro 2015-02-02 01:27:01 CST
>Commit d739846 fixes the unresponsive GUI and application crash described in 
>comment 17.

Commit d739846 has been ported to r14.0.x as commit b9346aa.
Comment 22 Darrell 2015-02-02 10:51:06 CST
Everything here is much improved. No window blanking, the Stop button now works, and good visual feedback for deep searches.

I do not see a keyboard shortcut for stopping a search, but as the toolbar now functions that is a small observation.
Comment 23 Michele Calgaro 2015-02-02 16:13:34 CST
>I do not see a keyboard shortcut for stopping a search, but as the toolbar now 
>functions that is a small observation.
It can be setup using the Configure Shortcuts.
Comment 24 Darrell 2015-02-04 12:11:37 CST
>It can be setup using the Configure Shortcuts.
Yes. I meant to write that there should be a built-in default, such as Esc.