<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On May 17, 2018, at 5:28 AM, Gábor Horváth via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><div class="">Hi Alexey,</div><div class=""><br class=""></div><div class="">In general, I like the idea of having a more declarative way to define new</div><div class="">checks.<br class=""></div><div class=""><br class=""></div><div class=""><div class="gmail_quote"><div dir="ltr" class="">On Thu, 17 May 2018 at 01:37, Alexey Sidorin <<a href="mailto:alexey.v.sidorin@ya.ru" class="">alexey.v.sidorin@ya.ru</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;">Hello everyone,<br class=""><br class="">I'd like to share some results of my investigation targeted on<span class="Apple-converted-space"> </span><br class="">improvement of Clang Static Analyzer checker API. You can find some<span class="Apple-converted-space"> </span><br class="">previous conversation on this topic here:<span class="Apple-converted-space"> </span><br class=""><a href="http://clang-developers.42468.n3.nabble.com/analyzer-RFC-Design-idea-separate-modelling-from-checking-td4059122.html" rel="noreferrer" target="_blank" class="">http://clang-developers.42468.n3.nabble.com/analyzer-RFC-Design-idea-separate-modelling-from-checking-td4059122.html</a>.<span class="Apple-converted-space"> </span><br class="">In my investigation, I tried to solve a particular problem of building a<span class="Apple-converted-space"> </span><br class="">checker without generating new nodes.<br class=""></blockquote><div class=""><br class=""></div><div class="">Why do you focus on such checks that does not have traits, does not generate new nodes.<span class="Apple-converted-space"> </span><br class=""></div><div class="">Do you find this to be the majority of the checks you need to implement?<span class="Apple-converted-space"> </span><br class=""></div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">--------- Introduction and design goals ---------<br class=""><br class="">In brief, I tried to use matchers-like API to make CSA checkers look<span class="Apple-converted-space"> </span><br class="">like this:<br class=""><br class="">StatementMatcher NotChdir =<br class="">    <span class="Apple-converted-space"> </span>callExpr(unless(callee(functionDecl(hasName("::chdir")))));<br class="">Finder.addMatcher(<br class="">    <span class="Apple-converted-space"> </span>hasSequence(<br class="">        <span class="Apple-converted-space"> </span>postStmt(hasStatement(<br class="">            <span class="Apple-converted-space"> </span>callExpr(callee(functionDecl(hasName("::chroot")))))),<br class="">        <span class="Apple-converted-space"> </span>unless(stmtPoint(hasStatement(callExpr(<br class="">            <span class="Apple-converted-space"> </span>callee(functionDecl(hasName("::chdir"))),<br class="">            <span class="Apple-converted-space"> </span>hasArgument(0, hasValue(stringRegion(refersString("/")))))))),<br class="">        <span class="Apple-converted-space"> </span>explodedNode(anyOf(postStmt(hasStatement(NotChdir)),<br class="">                            <span class="Apple-converted-space"> </span>callEnter(hasCallExpr(NotChdir))))<br class="">            <span class="Apple-converted-space"> </span>.bind("bug_node")),<br class="">    <span class="Apple-converted-space"> </span>&Callback);<br class="">Finder.match(G);<br class=""></blockquote><div class=""><br class=""></div><div class="">I think, a common (design) pitfall of writing checks is to try to match against</div><div class="">the AST when a symbolic execution callback should be used instead.</div><div class="">I am a bit afraid having an API like this would make this pitfall more common.</div><div class="">Maybe a separation between the path sensitive, flow sensitive and</div><div class="">AST based checks is good for the checker writers and new users and</div><div class="">I am not sure that the same abstraction fits all of these cases.</div><div class=""><br class=""></div><div class="">In case of path sensitive checks I wonder if a state machine like abstraction would</div><div class="">fit the use cases better (and also cover checks that are using traits)</div><div class="">where the guarding conditions of the state transitions can include AST matcher like checks.<span class="Apple-converted-space"> </span><br class=""></div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">and I have managed to make some simple working examples.<br class=""><br class="">The entire diff can be found here:<span class="Apple-converted-space"> </span><br class=""><a href="https://github.com/a-sid/clang/commit/9a0b1d1d9b3cf41b551a663f041f54d5427aa72f" rel="noreferrer" target="_blank" class="">https://github.com/a-sid/clang/commit/9a0b1d1d9b3cf41b551a663f041f54d5427aa72f</a><br class="">The code itself:<span class="Apple-converted-space"> </span><a href="https://github.com/a-sid/clang/tree/a4" rel="noreferrer" target="_blank" class="">https://github.com/a-sid/clang/tree/a4</a><br class=""><br class="">There are several reasons why I have tried this approach.<br class=""><br class="">1. AST Matchers are already extensively used API for AST checking. They<span class="Apple-converted-space"> </span><br class="">are available both in Clang-Tidy and CSA. And I wanted to use existing<span class="Apple-converted-space"> </span><br class="">functionality as much as possible. So, I decided to extend an existing<span class="Apple-converted-space"> </span><br class="">API to make its usage seamless across different kinds of checks:<span class="Apple-converted-space"> </span><br class="">path-sensitive, AST-based and CFG-based.<br class=""></blockquote><div class=""><br class=""></div><div class="">I am not sure if this is a good idea. I think the checker author supposed to</div><div class="">be aware if the check is AST based, flow sensitive, or path sensitive.<span class="Apple-converted-space"> </span><br class=""></div><div class="">And this should also be easy to tell by reading the code. I am also not</div><div class="">sure whether there is an abstraction that fits all.</div><div class=""><br class=""></div><div class="">I think the reason why this idea works well for checks that only inspect the</div><div class="">exploded graph, because in this case we are still doing pattern matching on</div><div class="">graphs in a similar manner as doing pattern matching on the AST.</div><div class=""><br class=""></div><div class="">But does this generalize later on to stateful checks?<span class="Apple-converted-space"> </span><br class=""></div></div></div></div></div></blockquote><div><br class=""></div><div>From my understanding it would only allow matching properties representable as finite automatons,</div><div>so e.g. no retain/release matchers.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><div class=""><div class="gmail_quote"><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">2. AST matchers effectively help clients to avoid a lot of checking of<span class="Apple-converted-space"> </span><br class="">dyn_cast results. This feature not only makes them more convenient but<span class="Apple-converted-space"> </span><br class="">also more safe because, in my experience, forgetting a nullptr/None<span class="Apple-converted-space"> </span><br class="">check is a pretty common mistake for checker writers.<br class=""></blockquote><div class=""><br class=""></div><div class=""><div class="">I think if something cannot be null we should return references, otherwise</div><div class="">the client need to check for the pointer beeing null (unless there are some</div><div class="">dynamic invariant that would make the check redundant). If an API does</div><div class="">not match this philosophy, maybe we should fix the API first. </div><div class=""><br class=""></div><div class="">Regardless of fixing the API, I agree that it would be great to have higher</div><div class="">level APIs for checker authors.</div></div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">3. Testing of AST matchers don't require writing C++ code - it can be<span class="Apple-converted-space"> </span><br class="">done interactively with clang-query tool. And I believe that we need<span class="Apple-converted-space"> </span><br class="">similar functionality for CSA as well.<br class=""></blockquote><div class=""><br class=""></div>Having a query tool for exploded graphs could be very helpful, I agree.</div><div class="gmail_quote">These graphs tend to be very large and sometimes it is not trivial to</div><div class="gmail_quote">find the relevant parts during debugging.<br class=""></div><div class="gmail_quote"><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">I didn't want to replace existing checker API. Instead, I tried to make<span class="Apple-converted-space"> </span><br class="">new possibilities usable independently or together with existing.<br class=""><br class="">--------- Design and implementation ---------<br class=""><br class="">The implementation consisted of a number of steps.<br class=""><br class="">1. Allow matching nodes of path-sensitive graph like usual AST nodes. To<span class="Apple-converted-space"> </span><br class="">make this possible, three actions were needed:<br class="">  1.1. ASTTypeTraits and DynTypedNode were extended to support<span class="Apple-converted-space"> </span><br class="">path-sensitive nodes: ExplodedNode, ProgramState, SVal, SymExpr, etc.<span class="Apple-converted-space"> </span><br class=""></blockquote><div class=""><br class=""></div><div class="">I wonder, if in general it is a good idea to pattern match in checks on SymExpr.</div><div class="">A more general approach here would be to use the constraint solver for queries</div><div class="">in a similar manner how ProgramState::assume works.<br class=""></div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;">The implementation with graph node support is moved into a separate<span class="Apple-converted-space"> </span><br class="">class (ASTGraphTypeTraits) in ento namespace to resolve cyclic<span class="Apple-converted-space"> </span><br class="">dependencies (they are still exist, unfortunately, but are header-only,<span class="Apple-converted-space"> </span><br class="">so we can build the PoC).<br class="">  1.2. Some additions to AST matchers were made to add support for new<span class="Apple-converted-space"> </span><br class="">kinds of nodes.<br class="">  1.3. To make MatchFinder able to query specific options not supported<span class="Apple-converted-space"> </span><br class="">by pure AST, it was augmented with "Contexts". A matcher that needs to<span class="Apple-converted-space"> </span><br class="">query the path-sensitive engine asks the Finder for the required Context<span class="Apple-converted-space"> </span><br class="">which provides specific helper functions.<br class=""><br class="">As the result of this step, we are able to write matchers like<span class="Apple-converted-space"> </span><br class="">expr(hasArgument(0, hasValue(stringRegion(refersString("/"))))).<br class=""></blockquote><div class=""><br class=""></div><div class="">I think this is the part of the proposal that I like the most, it would be</div><div class="">a very concise way to write down guarding conditions.<br class=""></div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">2. Create an engine for graph exploration and matching.<br class="">  <span class="Apple-converted-space"> </span>Unlike normal AST matchers, hasSequence is a path-sensitive matcher.<span class="Apple-converted-space"> </span><br class="">It is launched against ExplodedGraph. These matchers are handled by<span class="Apple-converted-space"> </span><br class="">GraphMatchFinder object. While searching a graph, it collects matches.<span class="Apple-converted-space"> </span><br class="">Each match contains a pointer to the corresponding matcher and State ID<span class="Apple-converted-space"> </span><br class="">of this match. The way how matches are translated from one state ID to<span class="Apple-converted-space"> </span><br class="">another is determined by matcher operators.<br class=""></blockquote><div class=""><br class=""></div><div class="">Is this matching done after the exploded graph already built? If so,</div><div class="">these checks will be unable to generate sink nodes. I think having sink</div><div class="">nodes sometimes desirable even if the check itself does not have a trait.</div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><br class="">  <span class="Apple-converted-space"> </span>For example, SequenceVariadicOperator, which is the base of<span class="Apple-converted-space"> </span><br class="">hasSequence() matcher, has "positive" and "negative" sub-matches. Each<span class="Apple-converted-space"> </span><br class="">positive matcher has its corresponding State ID. In order to advance to<span class="Apple-converted-space"> </span><br class="">the next State ID, a node being matched should match all "negative"<span class="Apple-converted-space"> </span><br class="">matchers before the next "positive" matchers and the next "positive"<span class="Apple-converted-space"> </span><br class="">matcher itself. Failure in matching "negative" matcher discards the match.<br class=""><br class="">  <span class="Apple-converted-space"> </span>The role of GraphMatchFinder is similar to MatchFinder: it is only<span class="Apple-converted-space"> </span><br class="">responsible for graph exploration and keeping bound nodes and matchers.<br class=""><br class="">3. Manage bound nodes.<br class="">  <span class="Apple-converted-space"> </span>While matching a single graph node, BoundNodes from AST MatchFinder<span class="Apple-converted-space"> </span><br class="">are used. AST matchers for path-sensitive nodes support bindings<span class="Apple-converted-space"> </span><br class="">out-of-the-box. However, the situation with graph matching is a bit<span class="Apple-converted-space"> </span><br class="">different. For graph matching, we have another system of bound nodes.<span class="Apple-converted-space"> </span><br class="">Each graph node has a related map of bounds aka GDMTy (yes, the name is<span class="Apple-converted-space"> </span><br class="">not a coincidence). GDMTy is a mapping from match ID to BoundNodesMap<span class="Apple-converted-space"> </span><br class="">which, in part, is effectively a map from std::string to DynTypedNodes.<span class="Apple-converted-space"> </span><br class="">This look pretty much like how GDM is organized in ExplodedGraph, just<span class="Apple-converted-space"> </span><br class="">without one level of indirection (it can be added, though).<br class=""><br class="">  <span class="Apple-converted-space"> </span>MatchFinder contexts should allow support of their own bindings. This<span class="Apple-converted-space"> </span><br class="">is how equalsBoundNode() matcher works for path-sensitive nodes: it just<span class="Apple-converted-space"> </span><br class="">queries all available contexts for the binding.<br class=""><br class="">Finally, I have managed to make two checkers work in this way:<span class="Apple-converted-space"> </span><br class="">ChrootChecker (which is present in the introduction) and<span class="Apple-converted-space"> </span><br class="">TestAfterDivZeroChecker. Both them can be found in ChrootCheckerV2.cpp<span class="Apple-converted-space"> </span><br class="">and TestAfterDivZeroCheckerV2.cpp correspondingly. They act like normal<span class="Apple-converted-space"> </span><br class="">checkers: produce warnings and use visitors. The main difference is that<span class="Apple-converted-space"> </span><br class="">they cannot generate sinks and use checkEndAnalysis callback. The code<span class="Apple-converted-space"> </span><br class="">of these checkers can be found here:<br class=""><br class=""><a href="https://github.com/a-sid/clang/blob/a4/lib/StaticAnalyzer/Checkers/ChrootCheckerV2.cpp" rel="noreferrer" target="_blank" class="">https://github.com/a-sid/clang/blob/a4/lib/StaticAnalyzer/Checkers/ChrootCheckerV2.cpp</a><br class=""><a href="https://github.com/a-sid/clang/blob/a4/lib/StaticAnalyzer/Checkers/TestAfterDivZeroCheckerV2.cpp" rel="noreferrer" target="_blank" class="">https://github.com/a-sid/clang/blob/a4/lib/StaticAnalyzer/Checkers/TestAfterDivZeroCheckerV2.cpp</a><br class=""><br class=""><br class="">-------- Some features --------<br class=""><br class="">1.The design of bindings has an interesting consequence: it enables the<span class="Apple-converted-space"> </span><br class="">dynamic introspection of GDM which was pretty hard before. (Hello alpha<span class="Apple-converted-space"> </span><br class="">renaming?)<br class="">2. Nothing prevents matchers to be used with existing checker API for<span class="Apple-converted-space"> </span><br class="">simplifying conditional checking inside callbacks. The matchers are not<span class="Apple-converted-space"> </span><br class="">planned as the replacement for the current API, but look like a nice<span class="Apple-converted-space"> </span><br class="">complementary part.<br class="">3. Implicit conversion of Matcher<ProgramPoint> to Matcher<ExplodedNode><span class="Apple-converted-space"> </span><br class="">and Matcher<SymExpr || MemRegion> to Matcher<SVal> for writing shorter code.<br class=""><br class="">-------- Not implemented/not checked yet --------<br class="">I tried to keep the PoC as minimal as possible. As the result, some<span class="Apple-converted-space"> </span><br class="">features are not implemented yet, but I believe they can be added.<br class="">1. Usage of matchers inside checker callbacks<br class="">  <span class="Apple-converted-space"> </span>This is not exactly unimplemented, but is still untested.<br class="">2. Dynamic matchers (clang-query interface)<br class="">  <span class="Apple-converted-space"> </span>In addition to work for supporting dynamic nodes (I don't know how<span class="Apple-converted-space"> </span><br class="">many efforts it can take), we need to enable matching against AST nodes,<span class="Apple-converted-space"> </span><br class="">not graph. But it doesn't look as a problem, we can just make matchers<span class="Apple-converted-space"> </span><br class="">polymorphic.<br class="">3. Binding to successfully matched paths is not implemented yet - only<span class="Apple-converted-space"> </span><br class="">bindings to separate nodes. I wonder if we need path bindings at all.<br class="">4. Some corner cases are still FIXMEs: single-node sequences, for example.<br class="">5. GDM is not based on immutable data structures like it is done in CSA<span class="Apple-converted-space"> </span><br class="">- it is just an STL map. Its performance can be poor (full copy on every<span class="Apple-converted-space"> </span><br class="">new node), but I don't think that changing it to use immutable<span class="Apple-converted-space"> </span><br class="">structures is hard.<br class="">6. Matching on-the-fly<br class="">  <span class="Apple-converted-space"> </span>GraphMatchFinder should support on-the-fly matching during<span class="Apple-converted-space"> </span><br class="">ExplodedGraph building. For this support, we should just call its<span class="Apple-converted-space"> </span><br class="">advance() method each time a new node is created. However, this<span class="Apple-converted-space"> </span><br class="">possibility wasn't checked yet.<br class="">7. Matching CFG and CallGraph isn't implemented because it was<span class="Apple-converted-space"> </span><br class="">considered to be far out of simple PoC.<br class="">8. Only sequential matching is available now, and I didn't try to<span class="Apple-converted-space"> </span><br class="">implement other operators yet. So, implementing a checker similar to<span class="Apple-converted-space"> </span><br class="">PthreadLock can be tricky or even impossible for now.<br class=""><br class="">-------- Known and potential issues --------<br class=""> From matchers' side:<br class="">1. Some tests don't pass because they rely on the checker ability to<span class="Apple-converted-space"> </span><br class="">generate sink nodes. Our matchers cannot do it by design so tests don't<span class="Apple-converted-space"> </span><br class="">pass.<br class="">2. Representing checker bindings as a map can be less effective than<span class="Apple-converted-space"> </span><br class="">storing data in structures. I didn't measure the overhead, so I cannot<span class="Apple-converted-space"> </span><br class="">give any numbers.<br class="">3. Matchers are called on every node independently of its type. This is<span class="Apple-converted-space"> </span><br class="">not what CheckerManager does. I wonder if this detail can affect<span class="Apple-converted-space"> </span><br class="">performance as well.<br class="">4. Problems with cyclic dependencies. clangStaticAnalyzer has a<span class="Apple-converted-space"> </span><br class="">dependency on clangASTMatchers, therefore, clangASTMatchers cannot<span class="Apple-converted-space"> </span><br class="">depend on clangStaticAnalyzer. However, if we want ASTMatchers to<span class="Apple-converted-space"> </span><br class="">support static analyzer data structures, there should be a backward<span class="Apple-converted-space"> </span><br class="">dependency. Now this dependency is header-only.<br class="">5. Code duplication. This is mostly fine for a sandbox but needs to be<span class="Apple-converted-space"> </span><br class="">reduced.<br class=""><br class=""> From analyzer's side:<br class="">1. Many events are not reflected in the final ExplodedGraph. For<span class="Apple-converted-space"> </span><br class="">example, checkers can receive PointerEscape event, but the event itself<span class="Apple-converted-space"> </span><br class="">will not be recorded in the ExplodedGraph - only changes made by<span class="Apple-converted-space"> </span><br class="">checkers will. That's also true for Stmt nodes: I noticed same issues<span class="Apple-converted-space"> </span><br class="">with PostCondition. This makes matching a bit harder. Should we add some<span class="Apple-converted-space"> </span><br class="">information into ExplodedGraph?<br class="">2. (Minor) Some static analyzer data structures don't support<span class="Apple-converted-space"> </span><br class="">traditional LLVM casting methods (dyn_cast, isa) because they lack<span class="Apple-converted-space"> </span><br class="">classof() method. I have fixed this internally and will put a patch on<span class="Apple-converted-space"> </span><br class="">review soon.<br class=""><br class="">-------- Conclusion --------<br class="">Finally, there is a graph matching engine supporting basic functionality<span class="Apple-converted-space"> </span><br class="">and two checkers using it. I apologize for not starting the discussion<span class="Apple-converted-space"> </span><br class="">earlier, but I just wasn't sure that the approach will work. Is anybody<span class="Apple-converted-space"> </span><br class="">interested to have this stuff in upstream (maybe, changed or improved)?<span class="Apple-converted-space"> </span><br class="">If yes, I'll be happy to contribute this work patch-by-patch and<span class="Apple-converted-space"> </span><br class="">continue its improvement. If no - well, I had enough fun playing with it.<br class=""></blockquote><div class=""><br class=""></div><div class="">Thanks for sharing this results. Regardless of being upstreamed as is or</div><div class="">in a separate form or not at all, this is an interesting experiment for the</div><div class="">community.<span class="Apple-converted-space"> </span><br class=""></div><div class=""> </div></div></div></div><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">_______________________________________________</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">cfe-dev mailing list</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><a href="mailto:cfe-dev@lists.llvm.org" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">cfe-dev@lists.llvm.org</a><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a></div></blockquote></div><br class=""></body></html>