<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;
        color:black;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
pre
        {mso-style-priority:99;
        mso-style-link:"HTML Preformatted Char";
        margin:0cm;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Courier New";
        color:black;}
p.msonormal0, li.msonormal0, div.msonormal0
        {mso-style-name:msonormal;
        mso-margin-top-alt:auto;
        margin-right:0cm;
        mso-margin-bottom-alt:auto;
        margin-left:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;
        color:black;}
span.HTMLPreformattedChar
        {mso-style-name:"HTML Preformatted Char";
        mso-style-priority:99;
        mso-style-link:"HTML Preformatted";
        font-family:Consolas;
        color:black;}
span.EmailStyle20
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body bgcolor="white" lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span style="color:windowtext">Hello,<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext">Thank you for your answer.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext">I fully agree that this is a very difficult problem. Ideally the best solution would be a perfect region store and constraint solver, but we will not have it in the near future. So I accept your proposed approach.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext">However, I have some questions before starting a prototype solution. First of all I cannot find the code that rearranges comparisons of symbolic regions. My rearrangement patch only works if the analyzer option
 is enabled which is not. Furthermore it only works for symbols with constrained ranges. Where else are comparisons rearranged?<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext">It is also not completely clear for me where to put the code that generates the sink and restarts the analysis? (I am also not sure how to restart the analysis for the current function.) Where to record the
 aliasing? Maybe keep that record in the GDM for the restarted analysis and make SymbolManager look there for aliased pointers? I think the heuristics are the last to insert once the prototype is working.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext">Regards,<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="HU" style="color:windowtext">Ádám<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:windowtext"><o:p> </o:p></span></p>
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal"><b><span style="color:windowtext">From:</span></b><span style="color:windowtext"> Artem Dergachev <noqnoqneo@gmail.com>
<br>
<b>Sent:</b> 2019. június 10., hétfő 5:31<br>
<b>To:</b> Gábor Horváth <xazax.hun@gmail.com>; Ádám Balogh <adam.balogh@ericsson.com>; Artem Dergachev <adergachev@apple.com><br>
<b>Cc:</b> cfe-dev@lists.llvm.org<br>
<b>Subject:</b> Re: [cfe-dev] [Analyzer] Equality of pointers<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-bottom:12.0pt">I believe in our current situation we should simply generate a sink whenever we discover symbolic pointer aliasing, because RegionStore always implicitly assumes that there's no aliasing. Eg., consider:<br>
<br>
  void example1(int *x, int *y) {<br>
    *x = 1; // (SymRegion{reg_$1<x>}, 0, direct): 1 S32b<br>
    *y = 2; // (SymRegion{reg_$2<y>}, 0, direct): 2 S32b<br>
    if (x == y) {<br>
      // ???<br>
    }<br>
  }<br>
<br>
The correct way to model the then-branch of the if-statement is to figure out which of the bindings is *newer* and keep it; in this case it'll mean dropping the binding of 'x' and keeping the binding of 'y'. This would mean that the value of the common pointee
 of 'x' and 'y' would be equal to 2. However, in its current shape RegionStore simply does not track history of bindings. We can make it track the history, but it'll be a ridiculously complex data structure - and even the current simple structure is so complicated
 and messy that nobody understands how it works.<br>
<br>
All right, suppose we make a new Store implementation that'll handle aliasing perfectly and is otherwise perfect in every way. Suppose we also have a perfect constraint solver that knows that in the following code<br>
<br>
  void example2(int *x, int *y) {<br>
    if (*x > 5)<br>
      if (*y < 10)<br>
        if (x == y) {<br>
          // ???<br>
        }<br>
  }<br>
<br>
the valid constraint range for the common pointee of 'x' and 'y' would be [6, 9] (this won't be immediately solved by the Z3 solver because heap shape information still needs to be stuffed into it). Now, how about these examples?:<br>
<br>
  void example3(int *x, int *y) {<br>
    delete x;<br>
    if (x == y) {<br>
      // ???<br>
    }<br>
  }<br>
<br>
  void example4(int *x, int *y) {<br>
    delete x;<br>
    delete y;<br>
    if (x == y) {<br>
      // ???<br>
    }<br>
  }<br>
<br>
In example 3 the common pointee would be deleted. It'd cause a warning if 'y' is used later. In example 4 it's an outright retroactive double-free. We need to modify MallocChecker to handle both of these cases correctly.<br>
<br>
If the same happens to RetainCountChecker, we'll need to *add* reference counts of the two pointers together. That's already a large variety of very non-trivial operations that we need to perform. How about aliasing file descriptors (which aren't even necessarily
 pointers)? How about aliasing two mutexes one of which is locked and the other is unlocked? How much completely non-trivial and non-reusable code do we need to write in dozens of checkers to solve this problem, given that we can barely solve it for RegionStore?<br>
<br>
===========<br>
<br>
What we *can* do, however, is to not only generate the sink, but *restart* the analysis from the beginning, assuming that the two pointers point to the same memory from the start. Say, force the SymbolManager that's owned by this analysis's ExprEngine to produce
 reg_$1<x> whenever it's asked for reg_$2<y>. This would make sure that we don't make wrong assumptions in the first place, so that we didn't have to undo them in the middle of the analysis. This wouldn't require much checker-side support, so it'll be much
 more in the spirit of the Analyzer. And it's also much easier to implement. As usual, we'll need some heuristics to make sure we don't exponentially explode on the number of different combinations of pointers that can potentially alias.<br>
<br>
<o:p></o:p></p>
<div>
<p class="MsoNormal">On 05.06.2019 05:23, Gábor Horváth via cfe-dev wrote:<o:p></o:p></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt">Hi!<o:p></o:p></p>
</div>
<p class="MsoNormal">This is an excellent point and it is not easy to solve. One of the reason why your original idea is hard to implement is the following. Let's look at the code snippet below:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">void f(int *p, int *q) {</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">  int *p2 = p + 2;</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">  if (p == q) {</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">    // Here we learned something new about p2 as well.</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">    // So we might need to update all the symbolic expressions and bindings, not just p.</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">  }</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-family:"Courier New"">}</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt">I think your second idea should work well, but I have no idea about the performance implications. As a starting point we could implement your second solution and do some benchmarks both performance wise and
 looking at the results from some open source projects to see what happens to the false positive rate.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt">Out of curiosity, do we have the same problems with invalidations?<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">I am sure Artem will have some more to add but as far as I know he is busy with WWDC this week. <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Regards,<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">Gabor<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">On Tue, 4 Jun 2019 at 14:53, Ádám Balogh via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-right:0cm">
<div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">Hello,<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">This is not the first time that we are facing the following problem.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">Given a code that clears all non-sentinel elements from a circular double-linked list with sentinel element:<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">typedef struct ListNode {<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">  struct ListNode *next;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">  struct ListNode *prev;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">  void *data;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">} ListNode;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">void ListClear(ListNode *list) {<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">  while (list->next != list) {<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    ListNode *node = list->next;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->next->prev = node->prev;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->prev->next = node->next;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->next = NULL;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->prev = NULL;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    free(node);<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">  }<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">}<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">unix.Malloc Use after free is reported in the second iteration of the loop for `node`.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">This is not necessarily a false positive if analyzed top level. The function that clears the nodes of the list implicitly assumes that it is a consistent circular double-linked
 list with a sentinel node. However this invariant is not ensured anywhere inside the function. It is thus not known that the `prev` pointer of the first non-sentinel node points back to the sentinel node, neither is it known that applying a `prev` and a `next`
 after each other in any order leads back to the original node. Without these invariants the analyzer cannot know that after unlinking and freeing the first non-sentinel element and then taking again the first non-sentinel element is not equal to the original
 sentinel element. So it assumes that they are equal and used again after freeing its memory space. Thus from the perspective of the standalone function it can be a use-after-free situation.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">So I fixed the function by inserting assertions to ensure the invariant:<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">void ListClear(ListNode *list) {<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">  while (list->next != list) {<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    ListNode *node = list->next;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    assert(node->prev == list);<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    assert(node->next->prev == node);<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    assert(node->prev->next == node);<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->next->prev = node->prev;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->prev->next = node->next;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->next = NULL;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    node->prev = NULL;<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">    free(node);<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">  }<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">}<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">However, it did not help because the analyzer cannot handle equality of pointers correctly. If we have an assumption that two pointers are equal the analyzer still creates two symbolic
 regions and records a constraint that the symbols of the symbolic regions are equal. Later this constraint can be used for deciding whether they are equal or not but it does not handle them as the same region. So if we change the pointer `node->prev->next`
 to `node->next` then `node->prev->next` is changed but `list->next` not even if we assumed that they are the same. That is the reason the analyzer takes the freed region again in the next iteration of the loop and reports an error.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">A strange thing is that the constraint manager rearranges the comparison of the two symbols (of the symbolic regions) to a difference without `aggressive-binary-operation-simplification`
 disabled. (It should not do it even if this option is enabled since the ranges of symbolic values are not constrained to `MAX/4` of the type.)<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">The question is how to fix this. I think that if two pointers are the same, then they must point to exactly the same memory region which means exactly the same symbol if it is a
 symbolic region. Thus instead of assigning `$reg2` to `node->prev` and recording whether the range of `$reg2-$reg0` is `[0..0]` the analyzer should assign `$reg0` to `node->prev` which is the region of `list`. Similarly, `node->next->prev` should not become
 `$reg7` where the range of `$reg7-$reg1` is `[0..0]` and `node->prev->next ` should not become `$reg11` where the range of `$reg11-$reg1` is `[0..0]` but both should become `$reg1`. This way when we unlink `node` `node->next->prev` becomes `reg0` (thus the
 region of `list`) and `node->prev->next` e.g. `$reg2`. This way in the next iteration `node->next` is `$reg2` instead of the freed `$reg1` so the false warning goes away. Of course I know this is not easy to implement. If both pointers already have regions
 assigned then which one to chose and how to replace the other one?<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">Another solution could be iterating all the existing regions upon bindings and do the same binding to the regions equal to the affected region. (I hope I managed to express myself
 clearly enough here.)<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">This is an old weakness of the Analyzer which should be solved eventually because it causes false positives. A new constraint manager does not help because the problem is not there.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">Any ideas?<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">Regards,<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span lang="HU">Ádám</span><o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"><span lang="HU"> </span><o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
</div>
</div>
<p class="MsoNormal">_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="https://protect2.fireeye.com/url?k=e2ffb2bd-be2bb821-e2fff226-8631fc8bdea5-f226057ee94a7815&q=1&u=https%3A%2F%2Flists.llvm.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fcfe-dev" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><o:p></o:p></p>
</blockquote>
</div>
<p class="MsoNormal"><br>
<br>
<o:p></o:p></p>
<pre>_______________________________________________<o:p></o:p></pre>
<pre>cfe-dev mailing list<o:p></o:p></pre>
<pre><a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a><o:p></o:p></pre>
<pre><a href="https://protect2.fireeye.com/url?k=561e6cb0-0aca662c-561e2c2b-8631fc8bdea5-1cb071bdb1502412&q=1&u=https%3A%2F%2Flists.llvm.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fcfe-dev">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><o:p></o:p></pre>
</blockquote>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</body>
</html>