<div style="font-family: arial, helvetica, sans-serif"><font size="2">+llvmdev, -llvm-dev<br><br><div class="gmail_quote">On Tue, Jun 26, 2012 at 2:28 PM, Kostya Serebryany <span dir="ltr"><<a href="mailto:kcc@google.com" target="_blank">kcc@google.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="font-family:arial,helvetica,sans-serif"><font size="2">Hi Reid, <br><br><div class="gmail_quote"><div><div class="h5">
On Tue, Jun 26, 2012 at 4:30 AM, Reid Watson <span dir="ltr"><<a href="mailto:reidw@google.com" target="_blank">reidw@google.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello,<br>
<br>
I'm starting work on a project to detect initialization order problems<br>
in C++ files using AddressSanitizer.<br>
The extension in question will hopefully result in AddressSanitizer<br>
being able to detect initializers which read an undefined value from a<br>
static or global variable defined in another TU.<br>
I'm currently working on this as a patch to AddressSanitizer, but I'm<br>
open to suggestions as to what the proper way to implement this<br>
extension would be.<br>
<br>
One of the simplest examples of this is the following example:<br>
It is undefined what this program will output, and it's fairly easy to<br>
see this behavior.<br>
<br>
When compiled as:<br>
$ clang++ file_1.cpp file_2.cpp main.cpp<br>
$./a.out<br>
x: 2<br>
y: 1<br>
<br>
However, when compiled as:<br>
$ clang++ file_2.cpp file_1.cpp main.cpp<br>
$./a.out<br>
x: 1<br>
y: 2<br>
<br>
//file_1.cpp<br>
extern int y;<br>
int x = y + 1;<br>
<br>
//file_2.cpp<br>
extern int x;<br>
int y = x + 1;<br>
<br>
//main.cpp<br>
#include <iostream><br>
extern int x,y;<br>
<br>
int main(){<br>
  std::cout << "x: " << x << std::endl;<br>
  std::cout << "y: " << y << std::endl;<br>
}<br>
<br>
Here's a sketch of the detection algorithm:<br>
For each TU:<br>
    1. Before each TU's initializers run, conditionally poison the<br>
global variable shadow memory<br>
        -Each global variable is poisoned, unless it was defined in that TU<br>
        -Additional information is added to struct __asan_global to<br>
identify which TU a global was declared in<br></blockquote><div><br></div></div></div><div>This could be tricky. </div><div>First, we don't want to poison the linker-initialized globals because they are always initialized regardless the TU order. </div>

<div><br></div><div>Second, consider we have 3 TUs, t1, t2, and t3, each has a global (g1, g2 and g3) with initializer.</div><div>When we are running initializers in t2, we need to poison g1 and g3, but so far we have seen only g1. </div>

<div>I don't know any good and portable way to get g3.</div><div><br></div><div>One solution is to run the binary twice: once with the default order of TU initializers, and second time with the reverted order (not sure if that's easy). </div>

<div><br></div><div>We probably don't want to do all that when initializing globals in a dlopen-ed library, or in any situation when we have multiple threads. </div><div class="im"><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


    2. Instrument all reads and writes in global initializers<br></blockquote><div><br></div></div><div>This has been fixed today (thanks Nick!)</div><div class="im"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


    3. After each TU's initializers run, we unpoison the shadow memory<br>
for all global variables<br></blockquote><div><br></div></div><div>Once we know what globals we need to poison, un-poisoning them is trivial. </div><div class="im"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


<br>
Note that once main has started running, AddressSanitizer will run<br>
normally.  This will result in AddressSanitizer catching all<br>
reads/writes to global variables defined in other TUs.<br>
We run all of AddressSanitizer after initialization because we cannot<br>
know prior to the completion of initialization which functions will be<br>
called from initializers.<br>
<br>
I'd welcome any feedback on this proposal!<br></blockquote><div><br></div></div><div>Sounds cool, make it happen! </div><div><br></div><div>--kcc </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


<br>
All the best,<br>
Reid<br>
</blockquote></div><br></font></div>
</blockquote></div><br></font></div>