Merge pull request #10486 from rjmccall/nested-access-tracking-4.0

[4.0] Fix some embarrassing list-management bugs with the exclusivity runtime
diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp
index a5101f9..6cc91c9 100644
--- a/stdlib/public/runtime/Exclusivity.cpp
+++ b/stdlib/public/runtime/Exclusivity.cpp
@@ -150,7 +150,7 @@
 
   void setNext(Access *next) {
     NextAndAction =
-      reinterpret_cast<uintptr_t>(next) | (NextAndAction & NextMask);
+      reinterpret_cast<uintptr_t>(next) | (NextAndAction & ActionMask);
   }
 
   ExclusivityFlags getAccessAction() const {
@@ -209,8 +209,11 @@
       return;
     }
 
-    for (Access *last = cur; cur != nullptr; last = cur, cur = cur->getNext()) {
-      if (last == access) {
+    Access *last = cur;
+    for (cur = cur->getNext(); cur != nullptr;
+         last = cur, cur = cur->getNext()) {
+      assert(last->getNext() == cur);
+      if (cur == access) {
         last->setNext(cur->getNext());
         return;
       }
diff --git a/unittests/runtime/Exclusivity.cpp b/unittests/runtime/Exclusivity.cpp
index ab0e874..35a34fe 100644
--- a/unittests/runtime/Exclusivity.cpp
+++ b/unittests/runtime/Exclusivity.cpp
@@ -16,7 +16,7 @@
 
 using namespace swift;
 
-TEST(TextExclusivity, testNullPC) {
+TEST(TestExclusivity, testNullPC) {
   ValueBuffer scratch, scratch2;
   long var;
   swift_beginAccess(&var, &scratch,
@@ -29,7 +29,7 @@
   swift_endAccess(&scratch);
 }
 
-TEST(TextExclusivity, testPCOne) {
+TEST(TestExclusivity, testPCOne) {
   ValueBuffer scratch, scratch2;
   long var;
   swift_beginAccess(&var, &scratch,
@@ -42,7 +42,7 @@
   swift_endAccess(&scratch);
 }
 
-TEST(TextExclusivity, testBogusPC) {
+TEST(TestExclusivity, testBogusPC) {
   ValueBuffer scratch, scratch2;
   long var;
   swift_beginAccess(&var, &scratch,
@@ -54,3 +54,34 @@
   swift_endAccess(&scratch2);
   swift_endAccess(&scratch);
 }
+
+// rdar://32866493
+TEST(TestExclusivity, testNonNested) {
+  const int N = 5;
+  ValueBuffer scratches[N];
+  long vars[N];
+
+  auto begin = [&](unsigned i) {
+    assert(i < N);
+    swift_beginAccess(&vars[i], &scratches[i], ExclusivityFlags::Modify, 0);
+  };
+  auto end = [&](unsigned i) {
+    assert(i < N);
+    swift_endAccess(&scratches[i]);
+    memset(&scratches[i], /*gibberish*/ 0x99, sizeof(ValueBuffer));
+  };
+  auto accessAll = [&] {
+    for (unsigned i = 0; i != N; ++i) begin(i);
+    for (unsigned i = 0; i != N; ++i) end(i);
+  };
+
+  accessAll();
+  begin(0); begin(1); end(0); end(1);
+  begin(0); begin(1); end(0); end(1);
+  accessAll();
+  begin(1); begin(0); begin(2); end(0); end(2); end(1);
+  accessAll();
+  begin(0); begin(1); begin(2); begin(3); begin(4);
+  end(1); end(4); end(0); end(2); end(3);
+  accessAll();
+}