PDA

View Full Version : Why my walker application hangs due to fubction recursion



artt
10th December 2015, 01:41
I have the app that take the argument as the directory name (finally it should be whole disk C/D/E) and have static function ::walk for it and if the traversed item is directory it is launched the recursive ::walk - but as debugger shows -- if (f.isDir()) {
Filewalker::walk(f.absoluteFilePath());
} -- shows the error of sigsegf- segmentation fault-- and I do not know why-due to memory overload, or absent of explicit destructor, or absence of pointer realization of Qlists. The recutrsive error delivers at 4-5 recursion, despite at smaller folders with several folders and level of nesting -- the output is normal. How to absolve this issue or to know exact reason of hanging error?


#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <QFile>
#include <QIODevice>
#include <QDir>
#include <QFileInfoList>
#include <QFile>
#include <QList>
#include <QTextStream>
#include <QXmlStreamWriter>
#include <QtDebug>
#include <iostream>
class Filewalker {
public:
long length;
QString name;
QString path;
//static QList <Filewalker> listed;
static QList <QFileInfo> list;
Filewalker(long length1, QString name1, QString path1);
static void walk(QString path0);
static void writexmlfile(QString path1);
static void readxmlfile();
};

class Lister {
public:
static QList <Filewalker> listed;
//static QTextStream cout(FILE * fileHandle);
};

QList <Filewalker> Lister::listed;

Filewalker::Filewalker(long length1, QString name1, QString path1) {
length=length1;
name=name1;
path=path1;
//listed = QList <Filewalker>();
}

void Filewalker::walk(QString path0) {
QDir root(path0);
QList <QFileInfo> list = root.entryInfoList(QDir::Files|QDir::Dirs|QDir::No DotAndDotDot);
int s=sizeof(Lister::listed);
if (list.isEmpty()) return;
if (list.size()>100) return;
//int s=Lister::listed.size();
foreach (QFileInfo f, list) {
//if (Filewalker::listed.size()>55) break;
if (f.isDir()) {
Filewalker::walk(f.absoluteFilePath());
}
else {
Filewalker odyn (f.size(), f.fileName(), f.path());
Lister::listed.append(odyn);
//odyn.~Filewalker();
QTextStream cout(stdout,QIODevice::WriteOnly);
//cout<<"File:"<<f.size()<<" " << f.fileName()<<" " <<f.path()<<" "<<s<<"\n";
cout<<"File:"<<odyn.length<<" "<< odyn.name<<" "<<odyn.path<<" "<<s<<"\n";
//cout.~QTextStream();
}
}
list.~QList();
root.~QDir();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Filewalker::walk("C:\\Documents and Settings");
return a.exec();

}



Added after 8 minutes:

In reality the error message shows such text--"Filewalker.exe-the error is found. The application will be closed. Sorry for inconvenience.
If the work is not finished the workdata could be lost.
Pass Microsoft the knowledege about error" (it is my translation of message to english).
So error is on the part of microsoft - despite dozens of fileinfos is displayed.
But If i put ::walk(C:\Windows)--the biggest folder- I just see blinking cursor in the first line of console and its idling.

d_stranz
10th December 2015, 18:24
But If i put ::walk(C:\Windows)--the biggest folder- I just see blinking cursor in the first line of console and its idling.

The error is *yours*, not Microsoft's. "C:\Windows" doesn't exist. "C:\\Windows" might, though.



list.~QList();
root.~QDir();


Why on earth are you deleting things you create on the stack? This is only one of the many things wrong with your code that could cause a crash.

You aren't checking for symbolic links, which could lead to infinite recursion, stack overflow, and a crash.

Why are you creating multiple instances of FileWalker (with different initializations), when all of the FileWalker methods are static?

You create a FileLister instance on the stack (odyn), then you append it to a Lister's list, and then it goes out of scope when you exit the if() clause. What do you think will happen at that point?

Instead of just writing more random code and hoping something will work (as it appears you are doing), write down in words, not code, what your program should do, and then design some classes and logic that will accomplish that. What you have now is so confused and full of bugs that you would be better off just throwing it out and starting over.

And before you write more code, open your C++ book and learn the difference between object instances created on the stack and those created on the heap.

artt
10th December 2015, 23:20
Of course, I used "C:\\Windows" in code itself.

list.~QList();
root.~QDir(); - Do not return the error but it is really error to create such object on stack-

Filewalker odyn (f.size(), f.fileName(), f.path()) - but debugger return segmentation fault on recursion line or

QList <QFileInfo> list = root.entryInfoList(QDir::Files|QDir::Dirs|QDir::No DotAndDotDot); - in last case I cannot put it with new operator or pointers?? or it possible?
Just added (...QDir::NoSymLinks) -- the diplay appeared more restricted - just 2 lines of file properties instead about dozen in previous case.
"Why are you creating multiple instances of FileWalker (with different initializations), when all of the FileWalker methods are static?" - this lines I do not undestand.
Every filewalker for every file properties? "with different initializations" - what you mean under different initialization?
Of course I could use all static methods in anotehr class - f.e. in Lister -- but static variables and methods are some global ones- and are initialized before the object creation.
"You create a FileLister instance on the stack (odyn), then you append it to a Lister's list, and then it goes out of scope when you exit the if() clause." - here maybe I do not understand some c++ fundamentals (sepite I have read most of main C++ and recently Qt books) - "and then it goes out of scope when you exit the if() clause." - did it means that listed is not appended?
This program is some analogue of Java one - that was designed by me and works very well.
It first craete the vector(list, here, as Qvector has no append fuction). Then I could write this properties to file (but converted in xml in advance) or render directly from this list of Filewalker, transformed to xml, and displayed in some kind of Textarea(multiline). And this system should be able to search by file name (by Filewalker name fileds or by XML name field ).

Added after 58 minutes:

When I change to:
QList <Filewalker*> Lister::listed;
....Filewalker* odyn = new Filewalker (f.size(), f.fileName(), f.path());
I got the same result (about dozens of lines with results and filewalker.exe console (memory) crash).
When I add something lower - the destructor
delete odyn - I got even worse result witn about 5 lines of display.
...
Trying to put listed on heap I got
QList* <Filewalker*> Lister::listed=new QList <Filewalker*>(); -- expected constructor, destructor, or type conversion before '*' token. So I am doubted that I can initialize static list with new operator.
Anyway after some changes with new operator - one option brings the SIGSEGF error during debugging
under the line of:
QList <QFileInfo> list = root.entryInfoList(QDir::Files|QDir::Dirs|QDir::No DotAndDotDot);

Added after 31 minutes:

Without creating the Filewalker objects(odyn), just using fileinfo instances "f",

cout<<"File:"<<f.size()<<" " << f.fileName()<<" " <<f.path()<<" "<<s<<"\n";
I got the same results, and debugger show the recursion line. So in this case the issue is in recursion or
in QFileInfoList list as it probably could not be put at hip as it is using the factory method?
Anyway if just to transform qfileinfo to xml and add to xml file I need to use recursion.
In Java <<File[] list = root.listFiles();>> it is similar but works in memory management and the same recursion.

Without creating the Filewalker objects(odyn), just using fileinfo instances "f",

cout<<"File:"<<f.size()<<" " << f.fileName()<<" " <<f.path()<<" "<<s<<"\n";
I got the same results, and debugger show the recursion line. So in this case the issue is in recursion or
in QFileInfoList list as it probably could not be put at hip as it is using the factory method?
Anyway if just to transform qfileinfo to xml and add to xml file I need to use recursion.
In Java <<File[] list = root.listFiles();>> it is similar but works in memory management and the same recursion.

Added after 19 minutes:

Without creating the Filewalker objects(odyn), just using fileinfo instances "f",

cout<<"File:"<<f.size()<<" " << f.fileName()<<" " <<f.path()<<" "<<s<<"\n";
I got the same results, and debugger show the recursion line. So in this case the issue is in recursion or
in QFileInfoList list as it probably could not be put at hip as it is using the factory method?
Anyway if just to transform qfileinfo to xml and add to xml file I need to use recursion.
In Java <<File[] list = root.listFiles();>> it is similar but works in memory management and the same recursion.

artt
12th December 2015, 13:23
Can I ask a Qt technical support about how to put QFileInfoList on heap? As in my case I got just 15 results in console display(despite due to recursion).

anda_skoa
12th December 2015, 13:50
Can I ask a Qt technical support about how to put QFileInfoList on heap?

Not sure why you are asking this here, but the very point of having a support contract is that you can ask the support staff.

If you think it is worthwhile to spend your money on asking how to use the new operator on a type, then that is what you should do.
However, you might want to consider that any basic C++ tutorial will answer that as well.

Cheers,
_



as Qvector has no append fuction

Must be an error in the documentation the it claims (http://doc.qt.io/qt-5/qvector.html#append) there is.
Interestingly the source itself also claims (http://code.woboq.org/qt5/qtbase/src/corelib/tools/qvector.h.html#_ZN7QVector6appendERKT_) that.

artt
12th December 2015, 16:12
It should be "fine" mistake in QtAssistant.
Should the technical support payable?
You are probably wrong - I can use "new" operator but can it help- but probably should. As debugger in lower (not terminal) console show the heap memory corruption.
If you mean this approach ("new" by default) from http://stackoverflow.com/questions/6039188/are-data-structures-in-qt-on-the-heap-or-on-the-stack -
QFileInfoList * dirStuff = new QFileInfoList();
*dirStuff = dir->entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot |
QDir::System | QDir::Hidden);
I will check it.
As my QFileInfoList is on stack it can withstand just 15 items (in case of recursion, despite I do not know do the latter influence it).

anda_skoa
12th December 2015, 16:28
It should be "fine" mistake in QtAssistant.

QVector::append() is also listed in QtAssistant, it shows the same document as the online help



Should the technical support payable?

I am not sure what you mean.



If you mean this approach ("new" by default) from http://stackoverflow.com/questions/6...r-on-the-stack -

Yes. Really not related to Qt at all, that is what C++ uses for any type.





QFileInfoList * dirStuff = new QFileInfoList();
*dirStuff = dir->entryInfoList(QDir:irs | QDir::Files | QDir::NoDotAndDotDot |
QDir::System | QDir::Hidden);


That should work, if you need that for whatever reason.



As my QFileInfoList is on stack it can withstand just 15 items

QFileInfoList, or more generically QList<T>, can easily holds thousands of items even when allocated on the stack.
Because it allocates its memory on the heap.

Cheers,
_

artt
12th December 2015, 20:43
1. Really, QVector has append() function- as it is the first function in QAssistant-may I overlooked it.
2. Under "payable" I mean - should I pay for such technical support?
3. It is very interesting that we can stack initialized object with heap memory--despite it - I initialized the
QFileInfoList in heap memory (in the code lower) -- but it againt return the 15 results-so just 15 fileinfos processed.

QFileInfoList* list=new QFileInfoList();
*list = root.entryInfoList(QDir::Files|QDir::Dirs|QDir::No DotAndDotDot);
int s=sizeof(Lister::listed);
if (list->isEmpty()) return;
if (list->size()>100) return;
//int s=Lister::listed.size();
foreach (const QFileInfo &f, *list) {
//if (Filewalker::listed.size()>55) break;
if (f.isDir()) {
Filewalker::walk(f.absoluteFilePath());//SIGSEGV
}
else {
And in debug mode - it returns the SIGSEGV (segmentation violation) in recursive Filewalker::walk(f.absoluteFilePath());
In normal mode:I see the message--that app finished unexpectedly (or crashed in another line).//Sorry I could not provide exact message in english as it is not in English.
So I even could not know how to overcome SIGSEGV in recursive statement???

Added after 20 minutes:

*list = root->entryInfoList(QDir::Files|QDir::Dirs|QDir::NoDotAn dDotDot); -- it lead to error -
base operand of '->' has non-pointer type 'QDir'

Added after 18 minutes:

Here are the full description of crash in debugger:


Could not load shared library symbols for 13 libraries, e.g. C:\WINDOWS\system32\ntdll.dll.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?File:262144 ntuser.dat C:/Documents and Settings/All Users 4
Could not load shared library symbols for C:\WINDOWS\system32\winmm.dll.
Do you need "set solib-search-path" or "set sysroot"?Could not load shared library symbols for C:\WINDOWS\system32\uxtheme.dll.
.......
Do you need "set solib-search-path" or "set sysroot"?Could not load shared library symbols for C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll.
Do you need "set solib-search-path" or "set sysroot"?Could not load shared library symbols for C:\WINDOWS\system32\comctl32.dll.
......
Do you need "set solib-search-path" or "set sysroot"?File:32256 Windows Update.lnk C:/Documents and Settings/All Users/Главное меню 4
File:8192 111.lnk C:/Documents and Settings/All Users/Главное меню 4
Could not load shared library symbols for C:\WINDOWS\system32\mlang.dll.
Do you need "set solib-search-path" or "set sysroot"?File:348160 Portable License Utility.lnk C:/Documents and Settings/All Users/Главное меню/Программы/3ds max 7 4
Heap corruption detected at 00D21710

anda_skoa
13th December 2015, 12:29
2. Under "payable" I mean - should I pay for such technical support?

You were considering asking Qt technical support, so I assumed you either had a support contract or were considering getting one.
You can of course ask trivial C++ questions as part of that package, but why not spent the money when you are actually having a Qt related isssue?



It is very interesting that we can stack initialized object with heap memory

The code executed by an object's constructor has the same options as code running inside a function.
Since function code can allocate heap memory, so can the constructor.

Most non trivial classes do that in one way or another.



but it againt return the 15 results-so just 15 fileinfos processed.

If the directory only has 15 entries, then the entryInfoList() function will return 15 instances of QFileInfo. no matter how you store it.
Keeping the list on the stack will at least avoid having to deal with deletion, right now your code leaks the list.



*list = root->entryInfoList(QDir::Files|QDir:irs|QDir::NoDotAndD otDot); -- it lead to error -
base operand of '->' has non-pointer type 'QDir'

As the compiler said, "root" is not a pointer, "->" dereferences a pointer.

In any case, you might want to have a look at QDirIterator.

Cheers,
_

artt
13th December 2015, 14:46
It happened - so I do not need use QDirIterator, as it also should have issue with the recursion.
(But 15 results was displayed for 2 or 3 folders that have far more files).
To resolve issue it was really simple - just
to put the entrance(initial) directory in the heap memory, and delete it in the end.


QDir* root=new QDir(path0);
QFileInfoList* list=new QFileInfoList();
*list = root->entryInfoList(QDir::Files|QDir::Dirs|QDir::NoDotAn dDotDot);
........
And in the end of function--
delete root;
delete list;

As the list of fileinfos is the same for release and debug mode -- about of 5 thousands items- I think the issue
is resolved.
Despite - in debug mode -
there are 4-5 .lnk files with aforementioned error messages:
File:126976 Site Information.lnk C:/Documents and Settings/All Users/Главное меню/Программы/ 10.0/Utilities 4
Could not load shared library symbols for C:\WINDOWS\system32\shdocvw.dll.
Do you need "set solib-search-path" or "set sysroot"?Could not load shared library symbols for C:\WINDOWS\system32\crypt32.dll...
Anyway in this case I just display the qfileinfos. But I need also write it in Qlist of filewalker objects.

Added after 16 minutes:

But I cannot initialize QList* <Filewalker*> Lister::listed=new QList <Filewalker*>() to place it on heap (or how do do i correctly?);
Just on stack - QList <Filewalker*> Lister::listed;

anda_skoa
13th December 2015, 15:52
It happened - so I do not need use QDirIterator, as it also should have issue with the recursion.

QDirIterator does not have any problem with recursion



to put the entrance(initial) directory in the heap memory, and delete it in the end.

Which of course is effectively the same as putting it on the stack, just that you now have to be sure not to return before the end.



QList* <Filewalker*> Lister::listed=new QList <Filewalker*>()

Assuming you want a QList<Filewalker*> then use that as the type of the pointer for the variable.


QList<Filewalker*>* listed = ....;


Cheers,
_

artt
13th December 2015, 17:51
Yes it works.