[cfe-dev] Trouble using TextDiagnosticPrinter

Ray Zhang via cfe-dev cfe-dev at lists.llvm.org
Wed Oct 14 12:33:24 PDT 2020


Hi Billy,

I've also run into this issue but I skirted around it by creating a
FixItRewriter
<https://clang.llvm.org/doxygen/classclang_1_1FixItRewriter.html> which is
actually a DiagnosticConsumer which the diagnostics engine DOESN'T own.
Unsure if this is the same case that you're running into, but when I was
experiencing segfaults I found it to be an issue with lifetime management
for diagnostic consumers. YMMV since the issue is within the FixItRewriter
impl itself, but the class stores a pointer to the current diagnostic
engine's client before setting the instance of FixItRewriter as our own. If
we tell the engine to own the FixItRewriter, then the previous consumer is
destroyed, and our FixItRewriter is then pointing to a destroyed resource.
Can you try creating a std::unique_ptr for your own diagnostics consumer
and tell the engine not to own it? You'd have to take care of the storage
lifetime in this case.

Also, one more thing is, when the Builder object gets destroyed it performs
an Emit(), and if you previously Emit then it won't do a double-write. At
the closing curly brace of your VisitFunctionDecl, it may be a good idea to
check which consumer you are currently using. I did a GDB backtrace in my
situation at the end-curly-brace and found that the diagnostics consumer
used to emit the message was actually not the one I thought I was using.

Since I didn't use the Visitor pattern but rather the Matcher pattern, my
scope of how the two use cases differ are limited. Hope you find the bug!

Best,
Ray

On Wed, Oct 14, 2020 at 12:17 PM Billy O'Mahony via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> Hi,
>
> After much hacking I managed to write a DiagnosticConsumer that would emit
> some error messages for me. Kudos to Andrzej for his help.
>
> I was expecting that I would more or less automatically get filename, line
> number and some source location carets added and some nice coloured text on
> my console. So for that I think I might need to use TextDiagnosticPrinter?
> However when I try to setClient that in my ASTContext's diagEngine it
> segfaults when a diagnostic is emitted.
>
> I've tried looking in the clang/tools files for inspiration from
> other FrontendAction style tools but they either don't use
> TextDiagnosticPrinter or else they use some other clang infra
> like clang/Rewrite/Core/Rewriter.h.
>
> This really feels like it should be super simple but I'm finding it very
> frustrating. My tool is actually doing useful things to spot
> project-specific code defects but now adding something simple like neat
> error messages is turning into a total quagmire.
>
> Thanks,
> Billy.
>
> class MyDiagnosticConsumer : public clang::DiagnosticConsumer {
> public:
>     void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const
> clang::Diagnostic& Info) override {
>         llvm::SmallVector<char, 512> message;
>         Info.FormatDiagnostic(message);
>         llvm::errs() << message << '\n';
>          cout << "Hello HandleDiagnostic!" << endl;
>     }
> };
>
> class MyVisitor : public RecursiveASTVisitor<MyVisitor> {
> public:
>   explicit MyVisitor(ASTContext *context)
>     : mContext(context) {}
>
>   bool VisitFunctionDecl(FunctionDecl* fnDecl) {
>       // let's just issue an error on every function decl!
>
>       auto& diagEngine = mContext->getDiagnostics();
>       const auto ID =
> diagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
>                                                  "%0 declared? You
> insensitive clod!");
>       auto Builder = diagEngine.Report(fnDecl->getLocation(), ID);
>       Builder.AddString(fnDecl->getNameAsString());
>
> Builder.AddSourceRange(clang::CharSourceRange::getCharRange(call->getSourceRange()));
>       Builder.setForceEmit();  // <<< without this
> MyDiagnosticConsumer::HandleDiagnostic is never called !!
>
>       return true;
>   }
>
> private:
>   ASTContext *mContext;
> };
>
>
> class MyConsumer : public clang::ASTConsumer {
> public:
>   explicit MyConsumer(ASTContext *Context) : Visitor(Context) {
>
>       DiagnosticsEngine &diagEngine = Context->getDiagnostics();
>
>       // if I set my own DiagnosticsConsumer here it works (but no
> line/file info).
>       diagEngine.setClient(new MyDiagnosticConsumer(),
> /*ShouldOwnClient=*/true);
>
>       ---- OR ----
>
>       // if I set a TextDiagnosticPrinter it crashes later on
>       // At the point where I otherwise get an error like
> '.../include/bla.h' file not found.
>       IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new
> DiagnosticOptions();
>       TextDiagnosticPrinter *DiagClient =
>           new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
>       diagEngine.setClient(DiagClient, true); // true => shouldOwnClient
>   }
>
>   virtual void HandleTranslationUnit(clang::ASTContext &Context) {
>       auto Decls = Context.getTranslationUnitDecl()->decls();
>       auto &SM = Context.getSourceManager();
>       for (auto &Decl : Decls) {
>           const auto& FileID = SM.getFileID(Decl->getLocation());
>           if (FileID != SM.getMainFileID()) {
>               // Skip decls coming via #incl
>               continue;
>           }
>
>           Visitor.TraverseDecl(Decl);
>       }
>   }
>
> private:
>   MyVisitor Visitor;
> };
>
>
>
>
> Program received signal SIGSEGV, Segmentation fault.
> clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=...,
> Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,
>     FixItHints=..., D=...) at
> /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95
> 95        beginDiagnostic(D, Level);
> (gdb) bt
> #0  clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=...,
> Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,
>     FixItHints=..., D=...) at
> /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95
> #1  0x00000000084ce036 in clang::TextDiagnosticPrinter::HandleDiagnostic
> (this=0x9b22430, Level=clang::DiagnosticsEngine::Fatal, Info=...)
>     at
> /home/bomahony/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp:152
>
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20201014/f0f02a9c/attachment-0001.html>


More information about the cfe-dev mailing list