edoc-main Mailing List for EDoC++
Status: Beta
Brought to you by:
bjcosta
You can subscribe to this list here.
| 2007 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
(1) |
Oct
|
Nov
(4) |
Dec
(8) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
| 2009 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: Brendon C. <bre...@gm...> - 2009-06-11 20:24:16
|
Thanks for the report and the patch. I just started using 64 bit Ubuntu a few weeks ago and had the same problem. It is fixed in CVS, though the current fix does not always configure using --disable-multilib but allows you to pass any configure options you like to the GCC configure script from the EDoC++ configure script. I use --with-gcc-config="--disable-multilib". I will look into why GCC configures with multilib by default and decide If I should always pass --disable-multilib or stick with the GCC convention of always building with multilib enabled unless explicitly requested to disable it. Additionally there is a fix in CVS for a stack overflow bug in EDoC++ when reading embedded EDoC++ data from a binary file using libbfd. On newer Ubuntu systems this causes a crash with a stack smashing detected error. Checkout the head of CVS to get these updates. I will be releasing 0.2.2 very soon with these fixes. Thanks, Brendon. 2009/6/12 Austin Ziegler <hal...@gm...>: > gcc tries to build in multilib (32+64) mode by default, which fails on > 64-bit systems. > > The patch added to the tracker on SF fixes this by forcing > --disable-multilib. I also did "CFLAGS=-m64 CXXFLAGS=m64 ./configure" > before running. It seems to work. > > -austin > -- > Austin Ziegler * hal...@gm... * http://www.halostatue.ca/ > * au...@ha... * http://www.halostatue.ca/feed/ > * au...@zi... > > ------------------------------------------------------------------------------ > Crystal Reports - New Free Runtime and 30 Day Trial > Check out the new simplified licensing option that enables unlimited > royalty-free distribution of the report engine for externally facing > server and web deployment. > http://p.sf.net/sfu/businessobjects > _______________________________________________ > Edoc-main mailing list > Edo...@li... > https://lists.sourceforge.net/lists/listinfo/edoc-main > |
|
From: Austin Z. <hal...@gm...> - 2009-06-11 18:06:07
|
gcc tries to build in multilib (32+64) mode by default, which fails on 64-bit systems. The patch added to the tracker on SF fixes this by forcing --disable-multilib. I also did "CFLAGS=-m64 CXXFLAGS=m64 ./configure" before running. It seems to work. -austin -- Austin Ziegler * hal...@gm... * http://www.halostatue.ca/ * au...@ha... * http://www.halostatue.ca/feed/ * au...@zi... |
|
From: Brendon C. <bre...@gm...> - 2009-02-20 23:53:46
|
Version 0.2.1 of EDoC++ has just been released. This version includes a few minor bug fixes. EDoC++ is both a "lint-like" tool and a documentation tool that specialises in analysing and documenting the use of exceptions in C++ code. In particular, EDoC++ will produce a list of warnings and errors for poor usage of exceptions in C++ code. Additionally, EDoC++ can generate detailed documentation including a list of all exceptions thrown by the functions in a given code base. This documentation is saved in a format that can be parsed by doxygen and is useful for adding exception documentation to the API for a code library. For more information see the website: http://edoc.sourceforge.net/ If you find EDoC++ useful then consider recommending it to others, writing a review, or creating a blog post about it. If you do choose to post information about EDoC++ somewhere then please include a link to the EDoC++ home page: http://edoc.sourceforge.net/ |
|
From: Brendon C. <bre...@gm...> - 2008-10-16 11:01:47
|
Version 0.2.0 of EDoc++ has just been released. This version includes a few important bug fixes and additional features. The goal of EDoc++ is to alleviate many of the problems associated with using exceptions in C++. It performs compile time static analysis over C++ source code producing warnings and errors for poor or bad exception usage. In addition to this EDoc++ is capable of generating detailed documentation about exception propagation through all functions that can then be used by doxygen. Among other things this particular release adds: * Update from GCC 4.0.1 to 4.0.4 * Support for FreeBSD * Improved post processing speeds * Added exception verification checks (Warn when throwing from a destructor) * Various bug fixes For more information see the website: http://edoc.sourceforge.net/ or browse the manual: http://edoc.sourceforge.net/EDocManual/index.html or download it from: http://sourceforge.net/project/showfiles.php?group_id=181536&package_id=210346 Please send bug-reports or feature requests to: br...@ch... or sign up to the mailing list: http://lists.sourceforge.net/lists/listinfo/edoc-main |
|
From: Brendon C. <br...@ch...> - 2008-06-29 12:01:59
|
> I'm really, really anxious to try edoc out, but I'm having trouble. > First, it doesn't compile on Mac OS due to a lack of libbfd. I am sorry that building it has been such an ordeal... I cant do much about Mac OS since i don't have access to it anywhere, however i will install FreeBSD on a virtual machine and fix those problems for the next release which should be coming out in the next month and fixes a bug with the reporting of exception for virtual functions (Should have been much earlier but i have had a slight detour to playing an MMORPG instead :-) ) I have only tested EDoc++ with Linux, NetBSD and partially with cygwin. > Interestingly, configure checks for libbfd but doesn't consider its > absence a failure, even though the build will fail if libbfd is not > there. This is probably a bug. If libbfd is not on the system, it should just disable certain features. I.e. Embedding EDoc++ data in binary files which is a convenience thing. > Then I switched to FreeBSD. It took a little trickery to get the build > to work. I had to create a symbolic link to > /usr/local/lib/libpython2.5.so <http://libpython2.5.so>, since the edoc > build only looks for libpython. Then, my configure invocation looks like > this: > > LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include/python2.5 > LIBS=-lpthread ./configure > > Setting --with-libpython doesn't work, since you can't set it to > /usr/local due to the location of the headers. > There is a slight modification I have put into the configure script for allowing this. You should be able to specify both the header and lib dirs separately using a ':' I.e. ./configure --with-libpython=/usr/local/include/python2.5:/usr/local/lib > Then the build failed because bfd_utils.cpp does not include > <sys/stat.h>, even though it uses struct stat. That is a bug, thanks for the report. > It also fails while > building gcc due to conflicting declarations of the function strsignal, > which I resolved by commenting the edoc-included one out. > hmm. I dont remember using strsignal at all in my code/modifications of GCC so it must be a part of the official GCC source. I know different distributions often maintain patches of official source tarballs as part of their ports/pkgsrc/rpm source repositories. This may be one of those things that is done for FreeBSD. I would be interesting to try and compile the original GCC tarball without any EDoc++ patches applied. I assume that it would give the same results. There is little i can do about this particular problem at the moment except to document it. I cant maintain a set of patches against GCC for each platform it doesn't compile out of the box for. There were plans to make the EDoc++ GCC patch a GCC "plugin" instead, however the GCC maintainer (last time i checked) dont want to add this feature to GCC for ambiguity with licensing issues. If this could happen it would mean i don't need to patch GCC or even build GCC as part of EDoc++, but alas politics gets in the way of progress it seems... > Finally, with edoc successfully built on FreeBSD I get the following at > every invocation: > > $ edoc Connection.hpp > Filed opening file: Connection.hpp > Reason: Unknown file type. > $ > > It doesn't matter what input I give edoc. It will tell me that the file > type is unknown in every instance, without fail, even if the input is a > directory. > EDoc++ does not process source files directly, rather it uses the modified GCC to compile source files while annotating data about what is in the code, and then processes the data generated by GCC. Look at the basic usage section of the EDoc++ manual: http://edoc.sourceforge.net/EDocManual/ch06.html So for you example, i would assume you have some main.cpp file that uses this Connection.hpp header. To used EDoc++ with this it might look like: Assuming main.cpp uses this header... start_edoc.sh EDOC -> g++ -fedoc-file=myapp.edc main.cpp -o myapp EDOC -> edoc --format simple myapp.edc Just to describe what is going on here... * start_edoc.sh : Simply sets up a shell that has all environment variables set to use the EDoc++ tool chain (I.e. patched GCC) * g++ -fedoc-file=myapp.edc main.cpp -o myapp Compiles main.cpp into an executable: 'myapp', however also annotates information about function callgraph and exceptions. This annotation is placed in the file 'myapp.edc' * edoc --format simple myapp.edc This gets EDoc++ to look at the data and generate a 'simple' format information about the exception propagation for each function. That should get you started... |
|
From: Will M. <wil...@us...> - 2008-06-27 16:10:25
|
Hello, I'm really, really anxious to try edoc out, but I'm having trouble. First, it doesn't compile on Mac OS due to a lack of libbfd. Interestingly, configure checks for libbfd but doesn't consider its absence a failure, even though the build will fail if libbfd is not there. This is probably a bug. Then I switched to FreeBSD. It took a little trickery to get the build to work. I had to create a symbolic link to /usr/local/lib/libpython2.5.so, since the edoc build only looks for libpython. Then, my configure invocation looks like this: LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include/python2.5 LIBS=-lpthread ./configure Setting --with-libpython doesn't work, since you can't set it to /usr/local due to the location of the headers. Then the build failed because bfd_utils.cpp does not include <sys/stat.h>, even though it uses struct stat. It also fails while building gcc due to conflicting declarations of the function strsignal, which I resolved by commenting the edoc-included one out. Finally, with edoc successfully built on FreeBSD I get the following at every invocation: $ edoc Connection.hpp Filed opening file: Connection.hpp Reason: Unknown file type. $ It doesn't matter what input I give edoc. It will tell me that the file type is unknown in every instance, without fail, even if the input is a directory. Thanks for any help, Will |
|
From: Brendon C. <bc...@av...> - 2007-12-18 05:52:37
|
Niko Ritari wrote: > With the following code, EDoc++ emits the warning "WARNING(WUNIMPL): > Function used but no implementation found : A::f()", and doesn't see the > exception from C::f(). > This is a bug. I have written a test for it using your example and have an idea of where the problem lies (In the GCC code that matches up virtual functions in a class hierarchy). Thanks for the report. Brendon. |
|
From: Brendon C. <bc...@av...> - 2007-12-18 05:50:43
|
Niko Ritari wrote:
> On Tue, 2007-12-11 at 14:35 +1100, Brendon Costa wrote:
> Ignore this part if you want to. I'm failing to understand why EDoc++
> works like it does with the simplest of test programs:
>
> void f() {
> try {
> throw;
> } catch (int) { }
> }
>
> int main() {
> try {
> throw 0;
> } catch (int) {
> f();
> }
> }
>
> Here, EDoc++ issues a WUNUSED_CATCH about the catch block in f. With the
> quoted explanation (about "MAYBE catching"), I don't see why. It also
> tells me int may propagate out of main, but that's to be expected when
> exceptions out of f is approximated to "...", without excluding int.
>
The current method is not accurate. It is a best effort approach that
will produce more warnings/errors than may be necessary. It should
however not silently skip over problems.
That above is another item to add to the tests and see exactly what is
happening. Again i dont have the time right now to look at it in more
detail, but i agree that it should not be emitting the WUNUSED_CATCH
as it should process the catch block with a partial match to type
"...". It could be that since EDoc++ can not tell if the catch block
will be used, it will emit the warning anyway.
>> That iterative approach might just work quite well! Start with a
>> complete union and iterate until nothing changes or some maximum
>> value... It certainly is worth looking into and I think it will be
>> much faster than the current method.
>
> I would still very much prefer it without the union, getting the exact
> result with the drawback of having to execute the algorithm to
> completion in order to avoid false negatives. Ideally, implement both,
> so that the user can choose the union method if the unoptimized exact
> one is too slow. It wouldn't probably even take many lines of extra code
> on top of a union + iteration implementation, just start with empty sets
> instead of the union.
>
> It's too easy to think of programs where two functions get a long list
> of bogus exceptions from the union, and keep passing them to each other.
>
Again. I am keen to solve this problem as best I can. You have given
me some options to follow. Its just that the period around Christmas
is bad for finding spare time.
> This sounds good enough. Either more or less work for the user depending
> on the program, clearer code with typedefs, and no need to know the
> possible exceptions.
>
> Unfortunately, this leaves the user the responsibility of avoiding an
> equivalent of "t2 = Type1DoStuff1;", whereas the compiler should
> automatically check the exception specifications.
>
I agree here, but there is not much i can think of to solve the
problem otherwise. Leaving too much responsibility for the user
introduces more places for errors to occur, but it is just a difficult
problem trying to automate this.
> However, the exception specification approach just lost a lot of its
> appeal: It seems that currently GCC (at least a not-so-current 4.1.1)
> actually does not check exception specs in any way in function pointer
> assignment. Funny enough, it does check them in overriding virtual
> functions.
>
Yep. The whole exception spec thing in C++ has been poorly thought
about and poorly implemented in my view. I can understand some peoples
reasoning for the way it is, but there would not be a need for EDoc++
if the C++ language had better support for exceptions.
Thanks,
Brendon.
|
|
From: Niko R. <nr...@mb...> - 2007-12-16 16:17:13
|
On Tue, 2007-12-11 at 14:35 +1100, Brendon Costa wrote:
> The only thing that filters out (sinks) a "..." exception type is a
> catch(...) All other catch handlers are considered to MAYBE catch this
> exception, but they can never sink it. There was a plan to store for
> each "..." exception a list of types that wont be rethrown, but that
> is not implemented and last time i thought through the consequences of
> doing so it started to make my head hurt. So i left it in the too hard
> basket.
Ignore this part if you want to. I'm failing to understand why EDoc++
works like it does with the simplest of test programs:
void f() {
try {
throw;
} catch (int) { }
}
int main() {
try {
throw 0;
} catch (int) {
f();
}
}
Here, EDoc++ issues a WUNUSED_CATCH about the catch block in f. With the
quoted explanation (about "MAYBE catching"), I don't see why. It also
tells me int may propagate out of main, but that's to be expected when
exceptions out of f is approximated to "...", without excluding int.
> > storing the joint lists of emitted exceptions for function classes
>
> I will look into it more later. For the normal case though this will
> use more memory and have very little gain in speed.
Not that much more memory. The set of exceptions for every function is
already stored. Also storing the union for the class isn't much more,
considering that every function only belongs to one class and functions
only called directly don't need class information.
Obviously the speedup is dependent on the size of the classes.
Importantly, how many functions with identical signature are used
through function pointers.
Not really knowing the code or having done any profiling, it's hard to
say how much time is generally spent in gathering exception sets from
called functions.
Anyway, this probably is far from the most important optimization, it's
just the only one I could think of in the context.
> That iterative approach might just work quite well! Start with a
> complete union and iterate until nothing changes or some maximum
> value... It certainly is worth looking into and I think it will be
> much faster than the current method.
I would still very much prefer it without the union, getting the exact
result with the drawback of having to execute the algorithm to
completion in order to avoid false negatives. Ideally, implement both,
so that the user can choose the union method if the unoptimized exact
one is too slow. It wouldn't probably even take many lines of extra code
on top of a union + iteration implementation, just start with empty sets
instead of the union.
It's too easy to think of programs where two functions get a long list
of bogus exceptions from the union, and keep passing them to each other.
> > By adding exception specifications to the function pointers
> > themselves, the list of functions possibly referenced by a given
> > function pointer could be reduced
>
> This is possible, and a much smaller task than monitoring assignment
> of function pointers and where they are passed to. A better option
> that unfortunatly will require a slight modification to the users code
> is to name all the functions of a particular group with a certain
> naming convention. E.g.:
[...]
> In the above if Type1 functions can only be assigned to t1 and Type2
> functions to t2. Then a very simple suppression could be written in a
> couple of lines by matching in the start of the function names.
This sounds good enough. Either more or less work for the user depending
on the program, clearer code with typedefs, and no need to know the
possible exceptions.
Unfortunately, this leaves the user the responsibility of avoiding an
equivalent of "t2 = Type1DoStuff1;", whereas the compiler should
automatically check the exception specifications.
However, the exception specification approach just lost a lot of its
appeal: It seems that currently GCC (at least a not-so-current 4.1.1)
actually does not check exception specs in any way in function pointer
assignment. Funny enough, it does check them in overriding virtual
functions.
--
Niko Ritari
|
|
From: Niko R. <nr...@mb...> - 2007-12-12 20:05:49
|
With the following code, EDoc++ emits the warning "WARNING(WUNIMPL):
Function used but no implementation found : A::f()", and doesn't see the
exception from C::f().
struct A {
virtual ~A() { }
virtual void f() = 0;
};
struct B : public A { };
struct C : public B {
virtual void f() { throw 0; }
};
int main() {
C c;
A& ra = c;
ra.f();
}
With any mention of f() in B, both problems go away. For example:
struct B : public A {
virtual void f() = 0;
};
If either A::f() is defined ("{ }" instead of "= 0") or another class
that implements f() is derived from A, the WUNIMPL naturally goes away,
but the exception from C::f() still isn't seen.
Other than that, probably anything can be added to the program without
changing this behavior.
PS. I'm still going to reply to the other topic when I find the time.
--
Niko Ritari
|
|
From: Brendon C. <bc...@av...> - 2007-12-05 04:48:17
|
Niko Ritari wrote: > On Tue, 2007-11-27 at 08:25 +1100, Brendon Costa wrote: >> The warnings/errors I thought MIGHT be affected specifically relate to >> situations where the currently caught exception is re-thrown from a >> called function. This should emit a warning anyway for exception type >> "..." being thrown from a no-throw function. An example follows: > > Obviously this is something I never thought about. To be honest, I > didn't know it was even possible. If this is important enough, perhaps > functions that re-throw outside a catch block could be detected and > always expanded, throw() or not. > Neither did I until a long way through writing the code for EDoc++ and I looked more at how GCC implements exception handling. > Would you care to explain briefly how EDoc++ currently handles these > situations? I don't see how it can sensibly process a function with a > naked "throw;" without knowing the context it's called in (especially > since there may be multiple potential callers), or does it somehow > descend to such functions from each caller unlike its normal behaviour > of only processing each function without circular dependencies once? EDoc++ has a special exception type "..." which represents a rethrow exception. This may then be expanded by a calling function when it asks the function being called for its lists of exceptions. The exact algorithm is more detailed than the above explanation as you would probably expect. But in essence the algorithm is the same as would normally be used to handle a rethrow that is directly inside a catch block, its just that we handle this across function boundaries and use a exception type ... as a place holder. I am reasonably sure that the current implementation works fine. There are a number of automated tests to check this particular problem. I initially found the issue i think by trying to compile libstdc++ which seems to make use of the feature (But my memory is a bit fuzzy on this). > I was thinking about this, even though I'm not currently interested in > trying to implement anything myself. This seems like a somewhat > complicated instance of a common problem encountered for example in data > flow analysis in compilers, and infinitely more information can be found > elsewhere. By taking a sort of reverse approach, an accurate result > should be attainable with efficiency. The algorithm would be "pushing" > exceptions to calling functions, instead of "pulling" them from called > functions. > I have not looked in detail at your proposal to determine if it would work or not for EDoc++, though thanks for the info. I have to admit i did not think of doing it the way you described before so it may prove fruitful. For the moment it is infeasible to change the current implementation as from what i can see it would require a reasonably large modification. But I will look into it after a few things on my current list to be done before version 1.0.0 have been completed. > I'm not sure about the current algorithm, but given your results in > another message, it seems to be exponential on C. Even a naive > implementation that doesn't keep track of exceptions "seen" at > call-points should easily beat it, at least with a large circular part > of the call-graph. The current algorithm is slow for the circular case. I think that its efficiency for the non-circular case is currently acceptable though from my brief reading of your description of the other method it could be improved. With the union update i mentioned before it will make the circular case of the same order as that for the current non-circular case. > I'm sure there's quite a bit of code required to implement, let alone > optimize, this algorithm in EDoc++. Maybe too much considering the > problem that it solves. Or maybe there's something fundamental stopping > this from being viable at all. At least the above discussed case of > functions with naked "throw;"s may require special treatment. > > Hope you got something out of this even if you aren't going to try to > implement the algorithm. The explanation sure turned out longer than I > thought... > I appreciate the ideas. When i have a chance I will look more into how I might be able to use it to improve EDoc++. Honestly that wont be at least until mid next year though. I want to improve the integration of EDoc++ with GCC and doxygen before I do any large changes to the base EDoc++ application code. I am however interested in making EDoc++ as useful a tool as possible. This i think will include more in the way of speed optimizations for the future which may include that algorithm you described. Thanks for the info, Brendon. P.S. I should be able to get around to making a patch for the circular call graph using unions before or just after Christmas. |
|
From: Niko R. <nr...@mb...> - 2007-12-02 16:56:22
|
On Tue, 2007-11-27 at 08:25 +1100, Brendon Costa wrote:=20 > The warnings/errors I thought MIGHT be affected specifically relate to > situations where the currently caught exception is re-thrown from a > called function. This should emit a warning anyway for exception type > "..." being thrown from a no-throw function. An example follows: Obviously this is something I never thought about. To be honest, I didn't know it was even possible. If this is important enough, perhaps functions that re-throw outside a catch block could be detected and always expanded, throw() or not. Would you care to explain briefly how EDoc++ currently handles these situations? I don't see how it can sensibly process a function with a naked "throw;" without knowing the context it's called in (especially since there may be multiple potential callers), or does it somehow descend to such functions from each caller unlike its normal behaviour of only processing each function without circular dependencies once? > While processing a function we look at all functions it calls and add > their exceptions to the current functions list (A little bit more > complex than that but that is the gist). [...]=20 > The issue discussed before arises only with circular callgraph > dependencies. In this case the called function is not guaranteed to have > already been processed before and so EDoc++ will descend into that > functions implementation temporarily to determine what it might throw. I was thinking about this, even though I'm not currently interested in trying to implement anything myself. This seems like a somewhat complicated instance of a common problem encountered for example in data flow analysis in compilers, and infinitely more information can be found elsewhere. By taking a sort of reverse approach, an accurate result should be attainable with efficiency. The algorithm would be "pushing" exceptions to calling functions, instead of "pulling" them from called functions. My explanation may be too detailed, I hope it's still understandable. The algorithm could begin by propagating exceptions in the functions not involved in circular paths in the regular, more efficient way. After that, each function in the remaining call graph has a known set of exceptions it may either throw directly or propagate from the already processed functions it may call. This set will be expanded while the algorithm runs, and is all that we care about. To start with, a working set W is constructed of those functions that may call functions with non-empty sets of known exceptions. The rest is repeated while W is non-empty: Remove a function f from W. Propagate (known) exceptions through f. This could be optimized to only account for previously unknown exceptions. If new exceptions are added to f's set of known exceptions, add to W (if not in it already) all functions that contain potential calls to f. We would like to only add a caller if one or more of its "call-points" haven't yet "seen" some of f's (new) exceptions. What I'm calling call-points match function calls in source code, so that there can be multiple in a single function, but potential calls to any number of functions may originate at one call-point. A static call to f has never "seen" the new exceptions, but dynamic calls (including calls through function pointers) require more tracking if we want to be optimal. With a large number of potential called functions, this can be very significant. For a call-graph with N call-points and E exceptions possible on each call-point, and the worst case altogether, this needs (only) EN additions to W, if already seen exceptions per call-point are kept track of. The amount of processing per function removed from W is basically same as in the non-circular case, I'm guessing something like O(EN) ignoring the function size, so, O(E=B2N=B2) total. Fully optimized maybe only O(CEN) with C being the number of call-points to possibly call a single function. Optimizations in choosing the order of processing are also possible, potentially allowing more exceptions to be propagated at once, further approaching the non-circular case. I'm not sure about the current algorithm, but given your results in another message, it seems to be exponential on C. Even a naive implementation that doesn't keep track of exceptions "seen" at call-points should easily beat it, at least with a large circular part of the call-graph. I'm sure there's quite a bit of code required to implement, let alone optimize, this algorithm in EDoc++. Maybe too much considering the problem that it solves. Or maybe there's something fundamental stopping this from being viable at all. At least the above discussed case of functions with naked "throw;"s may require special treatment. Hope you got something out of this even if you aren't going to try to implement the algorithm. The explanation sure turned out longer than I thought... --=20 Niko Ritari |
|
From: Brendon C. <br...@ch...> - 2007-11-26 21:25:49
|
Lawrence Spector wrote:
> I saw your last post and I wanted to comment on one particular point.
>
>> Yes. From what i can see EDoc++ should be able to ignore processing the
>> callgraph of functions that are declared not to throw.
>
> I would agree with this if the discussions were involving a language like Java. However, in C++, I would disagree with this action, since C++ has no way of guaranteeing at compile-time that the throw specification was actually followed. Therefore, wouldn't it be advantageous to process in this scenario and perhaps report a warning if an exception could be thrown from a function declared to not throw?
>
> Let me know what you think.
>
I was not overly clear. Statically enforcing that the no-throw function
does not throw any exceptions will occur anyway at a different point in
time. You are right. One of the main reasons for creating EDoc++ is to
perform this static enforcing of exception specifications. I will not
sacrifice that for speed. Though the change of the implementation
mentioned will not stop those warnings/errors from being emitted.
The warnings/errors I thought MIGHT be affected specifically relate to
situations where the currently caught exception is re-thrown from a
called function. This should emit a warning anyway for exception type
"..." being thrown from a no-throw function. An example follows:
void f1_invalid()
{
try{throw 2;}
catch(...){f2();}
}
void f1_valid()
{
try{throw 2.0f;}
catch(...){f2();}
}
void f2() throw()
{
try
{
// Rethrows the exception caught in f1() which is of type int
throw;
}
catch(float f){}
}
This is horrible code, but EDoc++ should handle it. The difficulty here
is that f2()'s no-throw spec will only be valid if the calling function
calls f2() from within a catch handler for a float. Otherwise it will
cause a terminate(). f1()_valid will not cause a terminate, but
f1_invalid() will. I hope i never see this kind of code but it is valid
C++ from what i know and GCC compiles and runs it as expected.
Following is a bit of an essay on how things are currently implemented
and what i plan to do. More for me to clarify it for myself i think :-)
Each function is processed individually by EDoc++ and when it is
processed its warnings/errors will be generated.
While processing a function we look at all functions it calls and add
their exceptions to the current functions list (A little bit more
complex than that but that is the gist). If the function being called is
declared no-throw then there is no need for EDoc++ to look any further
at that function as it will have no exceptions to add to the current
processing. The called function will however have been processed at an
earlier point in time, where errors would have already been emitted for
any exceptions that may try to pass through its no-throw specification.
The issue discussed before arises only with circular callgraph
dependencies. In this case the called function is not guaranteed to have
already been processed before and so EDoc++ will descend into that
functions implementation temporarily to determine what it might throw.
The circular callgraph handling is a little complex but was designed to
filter out as many exceptions that may occur as possible to reduce the
list of "possible" exceptions that may be filtered out by catch statements.
I am thinking of changing the implementation of how this is done to just
perform a union of all exceptions thrown from a set of functions in a
circular dependency instead of this more complex algorithm. It will make
processing these functions just as fast as that of non-circular
dependant functions at the cost of a larger set of "possible" exceptions
described as being thrown by a function. Even though those exceptions
should have been filtered out by catch statements.
There will of course be a command line option to re-enable the slow
method of calculation that is more accurate.
Brendon.
|
|
From: Lawrence S. <Law...@Ca...> - 2007-11-26 19:55:21
|
I saw your last post and I wanted to comment on one particular point. >Yes. From what i can see EDoc++ should be able to ignore processing the >callgraph of functions that are declared not to throw. I would agree with this if the discussions were involving a language like J= ava. However, in C++, I would disagree with this action, since C++ has no = way of guaranteeing at compile-time that the throw specification was actual= ly followed. Therefore, wouldn't it be advantageous to process in this sce= nario and perhaps report a warning if an exception could be thrown from a f= unction declared to not throw? Let me know what you think. Thanks, Lawrence -----Original Message----- From: edo...@li... [mailto:edoc-main-bounces@lis= ts.sourceforge.net] On Behalf Of Brendon Costa Sent: Friday, November 23, 2007 7:16 PM To: Niko Ritari Cc: edo...@li... Subject: Re: [Edoc-main] Skip throw() function pointers? Thanks for the feedback. It is good to hear other peoples experiences with EDoc++ and hopefully improve the tool in the process. Niko Ritari wrote: > Is it a valid idea to have EDoc++ skip pointers to functions that are > specified not to throw? > Yes. From what i can see EDoc++ should be able to ignore processing the callgraph of functions that are declared not to throw. I will look further into applying this optimisation for function pointers, virtual and normal functions. I can only see a few possible issues with the generation of warnings/errors but i have not yet looked into this. I am currently running a few tests that look like below: typedef void(*FuncPtr)(); f1() throw() {} f2() throw() {FuncPtr ptr =3D &f1; ptr();} f3() throw() {FuncPtr ptr =3D &f2; ptr();} ... f100() throw() {FuncPtr ptr =3D &f99; ptr();} int main() { f100(); } For 80 functions it took: 41 sec For 90 functions it took: 98 sec For 100 functions it took: 169 sec For 110 functions it took: 233 sec You can see the growth... This is the problem with "the special recursion case" as you mentioned. It may be possible to sacrifice some accuracy for more speed (I.e. More "possible" exceptions listed for functions in a cyclic graph). But i want to make sure that is where the time is being spent first by profiling the code. > If this is a valid approach, perhaps it could also be used to prune > direct and virtual calls to non-throwing functions. But maybe there is > some benefit in expanding those functions in the call graph, that I > don't see? > It would be a good optimisation. I will also see if there is anything that can be done for the generic case. I also want to see if it will cause any problems with the emission of certain warnings/errors that occur during processing if i omit the processing nothrow functions. > > PS. Loving the idea of EDoc++. I think it is really making exceptions in > C++ comfortable to work with. It's already found me a bug in an existing > program. > Thanks for the info :-) I am glad it has been of some use for someone else. I appreciate the effort you went to with the patch too. I will get back with more information when i have time to look into the problem in more detail. For now though the patch you provided should work for your project. Thanks, Brendon. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Edoc-main mailing list Edo...@li... https://lists.sourceforge.net/lists/listinfo/edoc-main |
|
From: Brendon C. <br...@ch...> - 2007-11-24 00:16:28
|
Thanks for the feedback. It is good to hear other peoples experiences
with EDoc++ and hopefully improve the tool in the process.
Niko Ritari wrote:
> Is it a valid idea to have EDoc++ skip pointers to functions that are
> specified not to throw?
>
Yes. From what i can see EDoc++ should be able to ignore processing the
callgraph of functions that are declared not to throw. I will look
further into applying this optimisation for function pointers, virtual
and normal functions. I can only see a few possible issues with the
generation of warnings/errors but i have not yet looked into this.
I am currently running a few tests that look like below:
typedef void(*FuncPtr)();
f1() throw() {}
f2() throw() {FuncPtr ptr = &f1; ptr();}
f3() throw() {FuncPtr ptr = &f2; ptr();}
...
f100() throw() {FuncPtr ptr = &f99; ptr();}
int main()
{
f100();
}
For 80 functions it took: 41 sec
For 90 functions it took: 98 sec
For 100 functions it took: 169 sec
For 110 functions it took: 233 sec
You can see the growth...
This is the problem with "the special recursion case" as you mentioned.
It may be possible to sacrifice some accuracy for more speed (I.e. More
"possible" exceptions listed for functions in a cyclic graph). But i
want to make sure that is where the time is being spent first by
profiling the code.
> If this is a valid approach, perhaps it could also be used to prune
> direct and virtual calls to non-throwing functions. But maybe there is
> some benefit in expanding those functions in the call graph, that I
> don't see?
>
It would be a good optimisation. I will also see if there is anything
that can be done for the generic case. I also want to see if it will
cause any problems with the emission of certain warnings/errors that
occur during processing if i omit the processing nothrow functions.
>
> PS. Loving the idea of EDoc++. I think it is really making exceptions in
> C++ comfortable to work with. It's already found me a bug in an existing
> program.
>
Thanks for the info :-) I am glad it has been of some use for someone
else. I appreciate the effort you went to with the patch too.
I will get back with more information when i have time to look into the
problem in more detail. For now though the patch you provided should
work for your project.
Thanks,
Brendon.
|
|
From: Niko R. <nr...@mb...> - 2007-11-23 11:54:40
|
Is it a valid idea to have EDoc++ skip pointers to functions that are specified not to throw? I'm running edoc on a medium sized program (50 kLOC) that uses lots of function pointers for various callback activities. After first processing the easy functions quite fast, it's running into an endless mess of "the special recursion case", slowly consuming more and more memory and taking at least an hour with a single function's call tree. My guess is, there is a serious combinatorial explosion of possible (as far as edoc knows) call graph loops, caused by lots of functions with identical signatures having their address taken and their own call graph again containing function pointer calls. However, most of the functions whose address is taken are declared throw(), and therefore shouldn't be interesting to potential callers from an exception viewpoint. I've tried a simple patch (attached) that simply ignores those functions, and it seems to work fine. The program in question is analysed in 30 seconds. If this is a valid approach, perhaps it could also be used to prune direct and virtual calls to non-throwing functions. But maybe there is some benefit in expanding those functions in the call graph, that I don't see? Of course this wouldn't help if the functions weren't throw(), but I didn't have enough interest to try to figure what else might be wrong, if indeed there is much that can be done without writing an extensive list of suppressions, restructuring the target program or rethinking the way EDoc++ propagates exception information. If you're interested and can give me something simplish to try, I will be happy to. PS. Loving the idea of EDoc++. I think it is really making exceptions in C++ comfortable to work with. It's already found me a bug in an existing program. -- Niko Ritari |
|
From: Brendon C. <br...@ch...> - 2007-09-05 12:25:30
|
Hi all, I will be away on holidays from the 6th of Sep 2007 - 1st of Oct. Just thought I will place a message here in case anyone has a question in that period. I will check my email every now and then but may not get a chance to answer any questions about EDoc++ until i return in October. Brendon. |
|
From: Brendon C. <br...@ch...> - 2007-08-12 12:13:45
|
Version 0.1.0 of EDoc++ has just been released. This version includes a few important bugfixes and a few additional features. EDoc++ is a tool that analyses exception usage in C++ source code to provide compile time/static analysis checks similar to that found in other languages such as Java. EDoc++ can also generate detailed information about exception propagation in various formats. One of which can be used by doxygen in documenting exception information for API's. Among other things this release adds: * Automatic import of EDoc++ data from shared libraries * Improved post processing speeds * Improved handling of recursive function calls * Downloadable binary packages for a few systems (A few more coming too) For more information see the website: http://edoc.sourceforge.net/ or browse the manual: http://edoc.sourceforge.net/EDocManual/index.html or download it from: http://sourceforge.net/project/showfiles.php?group_id=181536&package_id=210346 The above link currently contains a source tarball(edoc-0.1.0.tar.bz2), a Ubuntu Fiesty/debian package(edoc-0.1.0-1_i386.deb) and a cygwin binary package(edoc-0.1.0-1.tar.bz2). Please send bug-reports or feature requests to: br...@ch... or sign up to the mailing list: https://lists.sourceforge.net/lists/listinfo/edoc-main |
|
From: Brendon C. <br...@ch...> - 2007-04-21 02:04:09
|
The first release of EDoc++ has been made. Although titled an alpha release it should be completely functional. EDoc++ is a tool for performing static analysis of exception propagation through C++ source code. It also has the ability to document the propagation of exceptions in a format that can be used by Doxygen. For more information see the website: http://edoc.sourceforge.net/ or browse the manual: http://edoc.sourceforge.net/EDocManual/index.html or download it from (edoc-src-0.0.1.tar.bz2): http://sourceforge.net/project/showfiles.php?group_id=181536 |