Fix lsan errors

These leaks are all intentional, so this fixes them by deallocating them
only when asan is enabled.

To show them:
build/gen.py -d --use-asan
ninja -C out
out/gn_unittests

Change-Id: I937a4c33bfc6178cb42a61fc43e4da10d6668cc2
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/19000
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: Andrew Grieve <agrieve@google.com>
diff --git a/build/gen.py b/build/gen.py
index 5d07459..533df58 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -478,6 +478,7 @@
 
     if options.use_asan:
       cflags.append('-fsanitize=address')
+      cflags.append('-DASAN_ENABLED')
       ldflags.append('-fsanitize=address')
 
     if options.use_ubsan:
diff --git a/src/gn/command_gen.cc b/src/gn/command_gen.cc
index 3edee43..652c3e3 100644
--- a/src/gn/command_gen.cc
+++ b/src/gn/command_gen.cc
@@ -918,7 +918,9 @@
 
   // Just like the build graph, leak the resolved data to avoid expensive
   // process teardown here too.
+#ifndef ASAN_ENABLED
   write_info.LeakOnPurpose();
+#endif
 
   return 0;
 }
diff --git a/src/gn/string_atom.cc b/src/gn/string_atom.cc
index 5c3f73f..36f912f 100644
--- a/src/gn/string_atom.cc
+++ b/src/gn/string_atom.cc
@@ -114,12 +114,23 @@
     //
     // This allows the StringAtom() default initializer to use the same
     // address directly, avoiding a table lookup.
-    //
     size_t hash = set_.Hash("");
     auto* node = set_.Lookup(hash, "");
     set_.Insert(node, hash, &kEmptyString);
   }
 
+#ifdef ASAN_ENABLED
+  ~StringAtomSet() {
+    if (!slabs_.empty()) {
+      Slab* last_slab = slabs_.back();
+      for (Slab* slab : slabs_) {
+        slab->destroy(slab == last_slab ? slab_index_ : kStringsPerSlab);
+        delete slab;
+      }
+    }
+  }
+#endif
+
   // Find the unique constant string pointer for |key|.
   const std::string* find(std::string_view key) {
     std::lock_guard<std::mutex> lock(mutex_);
@@ -168,6 +179,12 @@
       return result;
     }
 
+    void destroy(size_t max_index) {
+      for (size_t i = 0; i < max_index; ++i) {
+        items_[i].str.~basic_string();
+      }
+    }
+
    private:
     StringStorage items_[kStringsPerSlab];
   };