Store RcFile pointers, rather than inline objects.

Since RcFile hands out pointers to its string members, modifying
vector<RcFile> may cause reallocation, which invalidates handed out
pointers.

Fixes #205.

--
Change-Id: Id4eb0a4e8a52373130140f1de5697f4e4f4a6f95
Reviewed-on: https://bazel-review.googlesource.com/#/c/1360/
MOS_MIGRATED_REVID=94276823
diff --git a/src/main/cpp/option_processor.cc b/src/main/cpp/option_processor.cc
index 9500cf4..9a14484 100644
--- a/src/main/cpp/option_processor.cc
+++ b/src/main/cpp/option_processor.cc
@@ -47,7 +47,7 @@
 }
 
 blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
-    vector<RcFile>* rcfiles,
+    vector<RcFile*>* rcfiles,
     map<string, vector<RcOption> >* rcoptions,
     string* error) {
   list<string> initial_import_stack;
@@ -57,12 +57,13 @@
 }
 
 blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
-    const string& filename,
+    const string& filename_ref,
     const int index,
-    vector<RcFile>* rcfiles,
+    vector<RcFile*>* rcfiles,
     map<string, vector<RcOption> >* rcoptions,
     list<string>* import_stack,
     string* error) {
+  string filename(filename_ref);  // file
   string contents;
   if (!ReadFile(filename, &contents)) {
     // We checked for file readability before, so this is unexpected.
@@ -121,10 +122,10 @@
         return blaze_exit_code::BAD_ARGV;
       }
 
-      rcfiles->push_back(RcFile(words[1], rcfiles->size()));
+      rcfiles->push_back(new RcFile(words[1], rcfiles->size()));
       import_stack->push_back(words[1]);
-      blaze_exit_code::ExitCode parse_exit_code = RcFile::Parse(
-          rcfiles->back().Filename(), rcfiles->back().Index(),
+      blaze_exit_code::ExitCode parse_exit_code =
+        RcFile::Parse(rcfiles->back()->Filename(), rcfiles->back()->Index(),
           rcfiles, rcoptions, import_stack, error);
       if (parse_exit_code != blaze_exit_code::SUCCESS) {
         return parse_exit_code;
@@ -260,18 +261,19 @@
   if (use_master_blazerc) {
     string depot_blazerc_path = FindDepotBlazerc(workspace);
     if (!depot_blazerc_path.empty()) {
-      blazercs_.push_back(RcFile(depot_blazerc_path, blazercs_.size()));
+      blazercs_.push_back(new RcFile(depot_blazerc_path, blazercs_.size()));
       blaze_exit_code::ExitCode parse_exit_code =
-          blazercs_.back().Parse(&blazercs_, &rcoptions_, error);
+          blazercs_.back()->Parse(&blazercs_, &rcoptions_, error);
       if (parse_exit_code != blaze_exit_code::SUCCESS) {
         return parse_exit_code;
       }
     }
     string alongside_binary_blazerc = FindAlongsideBinaryBlazerc(cwd, args[0]);
     if (!alongside_binary_blazerc.empty()) {
-      blazercs_.push_back(RcFile(alongside_binary_blazerc, blazercs_.size()));
+      blazercs_.push_back(new RcFile(alongside_binary_blazerc,
+          blazercs_.size()));
       blaze_exit_code::ExitCode parse_exit_code =
-          blazercs_.back().Parse(&blazercs_, &rcoptions_, error);
+          blazercs_.back()->Parse(&blazercs_, &rcoptions_, error);
       if (parse_exit_code != blaze_exit_code::SUCCESS) {
         return parse_exit_code;
       }
@@ -286,9 +288,9 @@
     return find_blazerc_exit_code;
   }
   if (!user_blazerc_path.empty()) {
-    blazercs_.push_back(RcFile(user_blazerc_path, blazercs_.size()));
+    blazercs_.push_back(new RcFile(user_blazerc_path, blazercs_.size()));
     blaze_exit_code::ExitCode parse_exit_code =
-        blazercs_.back().Parse(&blazercs_, &rcoptions_, error);
+        blazercs_.back()->Parse(&blazercs_, &rcoptions_, error);
     if (parse_exit_code != blaze_exit_code::SUCCESS) {
       return parse_exit_code;
     }
@@ -347,7 +349,7 @@
     // Process all elements except the last one.
     for (; i < startup_options.size() - 1; i++) {
       const RcOption& option = startup_options[i];
-      const string& blazerc = blazercs_[option.rcfile_index()].Filename();
+      const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
       process_arg_exit_code = parsed_startup_options_->ProcessArg(
           option.option(), startup_options[i + 1].option(), blazerc,
           &is_space_separated, error);
@@ -362,7 +364,7 @@
     if (i < startup_options.size()) {
       const RcOption& option = startup_options[i];
       if (IsArg(option.option())) {
-        const string& blazerc = blazercs_[option.rcfile_index()].Filename();
+        const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
         process_arg_exit_code = parsed_startup_options_->ProcessArg(
             option.option(), "", blazerc, &is_space_separated, error);
         if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
@@ -407,8 +409,8 @@
 void OptionProcessor::AddRcfileArgsAndOptions(bool batch, const string& cwd) {
   // Push the options mapping .blazerc numbers to filenames.
   for (int i_blazerc = 0; i_blazerc < blazercs_.size(); i_blazerc++) {
-    const RcFile& blazerc = blazercs_[i_blazerc];
-    command_arguments_.push_back("--rc_source=" + blazerc.Filename());
+    const RcFile* blazerc = blazercs_[i_blazerc];
+    command_arguments_.push_back("--rc_source=" + blazerc->Filename());
   }
 
   // Push the option defaults
@@ -462,4 +464,11 @@
 const BlazeStartupOptions& OptionProcessor::GetParsedStartupOptions() const {
   return *parsed_startup_options_.get();
 }
+
+OptionProcessor::~OptionProcessor() {
+  for (auto it : blazercs_) {
+    delete it;
+  }
+}
+
 }  // namespace blaze
diff --git a/src/main/cpp/option_processor.h b/src/main/cpp/option_processor.h
index 15724e8..5b12bcd 100644
--- a/src/main/cpp/option_processor.h
+++ b/src/main/cpp/option_processor.h
@@ -35,7 +35,7 @@
  public:
   OptionProcessor();
 
-  virtual ~OptionProcessor() {}
+  virtual ~OptionProcessor();
 
   // Parse a command line and the appropriate blazerc files. This should be
   // invoked only once per OptionProcessor object.
@@ -87,7 +87,7 @@
    public:
     RcFile(const string& filename, int index);
     blaze_exit_code::ExitCode Parse(
-        std::vector<RcFile>* rcfiles,
+        std::vector<RcFile*>* rcfiles,
         std::map<string, std::vector<RcOption> >* rcoptions,
         string* error);
     const string& Filename() const { return filename_; }
@@ -96,7 +96,7 @@
    private:
     static blaze_exit_code::ExitCode Parse(const string& filename,
                                            const int index,
-                                           std::vector<RcFile>* rcfiles,
+                                           std::vector<RcFile*>* rcfiles,
                                            std::map<string,
                                            std::vector<RcOption> >* rcoptions,
                                            std::list<string>* import_stack,
@@ -109,7 +109,7 @@
   void AddRcfileArgsAndOptions(bool batch, const string& cwd);
   blaze_exit_code::ExitCode ParseStartupOptions(string *error);
 
-  std::vector<RcFile> blazercs_;
+  std::vector<RcFile*> blazercs_;
   std::map<string, std::vector<RcOption> > rcoptions_;
   std::vector<string> args_;
   unsigned int startup_args_;