Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
273 views
in Technique[技术] by (71.8m points)

portability - Portable C++ Stack Trace on Exception

I am writing a library that I would like to be portable. Thus, it should not depend on glibc or Microsoft extensions or anything else that is not in the standard. I have a nice hierarchy of classes derived from std::exception that I use to handle errors in logic and input. Knowing that a particular type of exception was thrown at a particular file and line number is useful, but knowing how the execution got there would be potentially much more valuable, so I have been looking at ways of acquiring the stack trace.

I am aware that this data is available when building against glibc using the functions in execinfo.h (see question 76822) and through the StackWalk interface in Microsoft's C++ implementation (see question 126450), but I would very much like to avoid anything that is not portable.

I was thinking of implementing this functionality myself in this form:

class myException : public std::exception
{
public:
  ...
  void AddCall( std::string s )
  { m_vCallStack.push_back( s ); }
  std::string ToStr() const
  {
    std::string l_sRet = "";
    ...
    l_sRet += "Call stack:
";
    for( int i = 0; i < m_vCallStack.size(); i++ )
      l_sRet += "  " + m_vCallStack[i] + "
";
    ...
    return l_sRet;
  }
private:
  ...
  std::vector< std::string > m_vCallStack;
};

ret_type some_function( param_1, param_2, param_3 )
{
  try
  {
    ...
  }
  catch( myException e )
  {
    e.AddCall( "some_function( " + param_1 + ", " + param_2 + ", " + param_3 + " )" );
    throw e;
  }
}

int main( int argc, char * argv[] )
{
  try
  {
    ...
  }
  catch ( myException e )
  {
    std::cerr << "Caught exception: 
" << e.ToStr();
    return 1;
  }
  return 0;
}

Is this a terrible idea? It would mean a lot of work adding try/catch blocks to every function, but I can live with that. It would not work when the cause of the exception is memory corruption or lack of memory, but at that point you are pretty much screwed anyway. It may provide misleading information if some functions in the stack do not catch exceptions, add themselves to the list, and rethrow, but I can at least provide a guarantee that all of my library functions do so. Unlike a "real" stack trace I will not get the line number in calling functions, but at least I would have something.

My primary concern is the possibility that this will cause a slowdown even when no exceptions are actually thrown. Do all of these try/catch blocks require an additional set-up and tear-down on each function invocation, or is somehow handled at compile-time? Or are there other issues I have not considered?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think this is a really bad idea.

Portability is a very worthy goal, but not when it results in a solution that is intrusive, performance-sapping, and an inferior implementation.

Every platform (Windows/Linux/PS2/iPhone/etc) I've worked on has offered a way to walk the stack when an exception occurs and match addresses to function names. Yes, none of these are portable but the reporting framework can be and it usually takes less than a day or two to write a platform-specific version of stack walking code.

Not only is this less time than it'd take creating/maintaining a cross-platform solution, but the results are far better;

  • No need to modify functions
  • Traps crashes in standard or third party libraries
  • No need for a try/catch in every function (slow and memory intensive)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...