|  | commit 2cfbf2fece582c29df348104b28677c38a8301f4 | 
|  | Author: Cary Coutant <ccoutant@google.com> | 
|  | Date:   Tue Feb 3 19:54:57 2015 -0800 | 
|  |  | 
|  | Fix a file descriptor leak in gold. | 
|  |  | 
|  | When an LTO linker plugin claims an external member of a thin archive, gold | 
|  | does not properly unlock the file and make its file descriptor available for | 
|  | reuse. This patch fixes the problem by modifying Archive::include_member to | 
|  | unlock the object file via an RAII class instance, ensuring that it will be | 
|  | unlocked no matter what path is taken through the function. | 
|  |  | 
|  | gold/ | 
|  | PR gold/15660 | 
|  | * archive.cc (Thin_archive_object_unlocker): New class. | 
|  | (Archive::include_member): Unlock external members of thin archives. | 
|  | * testsuite/Makefile.am (plugin_test_1): Rename .syms files. | 
|  | (plugin_test_2): Likewise. | 
|  | (plugin_test_3): Likewise. | 
|  | (plugin_test_4): Likewise. | 
|  | (plugin_test_5): Likewise. | 
|  | (plugin_test_6): Likewise. | 
|  | (plugin_test_7): Likewise. | 
|  | (plugin_test_8): Likewise. | 
|  | (plugin_test_9): Likewise. | 
|  | (plugin_test_10): Likewise. | 
|  | (plugin_test_11): New test case. | 
|  | * testsuite/Makefile.in: Regenerate. | 
|  | * testsuite/plugin_test.c (claim_file_hook): Check for parallel .syms | 
|  | file to decide whether to claim file. | 
|  | (all_symbols_read_hook): Likewise. | 
|  | * testsuite/plugin_test_1.sh: Adjust expected output. | 
|  | * testsuite/plugin_test_2.sh: Likewise. | 
|  | * testsuite/plugin_test_3.sh: Likewise. | 
|  | * testsuite/plugin_test_6.sh: Likewise. | 
|  | * testsuite/plugin_test_tls.sh: Likewise. | 
|  | * testsuite/plugin_test_11.sh: New testcase. | 
|  |  | 
|  | diff --git a/gold/archive.cc b/gold/archive.cc | 
|  | index 69107f5..6d25980 100644 | 
|  | --- a/gold/archive.cc | 
|  | +++ b/gold/archive.cc | 
|  | @@ -930,6 +930,32 @@ Archive::count_members() | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | +// RAII class to ensure we unlock the object if it's a member of a | 
|  | +// thin archive. We can't use Task_lock_obj in Archive::include_member | 
|  | +// because the object file is already locked when it's opened by | 
|  | +// get_elf_object_for_member. | 
|  | + | 
|  | +class Thin_archive_object_unlocker | 
|  | +{ | 
|  | + public: | 
|  | +  Thin_archive_object_unlocker(const Task *task, Object* obj) | 
|  | +    : task_(task), obj_(obj) | 
|  | +  { } | 
|  | + | 
|  | +  ~Thin_archive_object_unlocker() | 
|  | +  { | 
|  | +    if (this->obj_->offset() == 0) | 
|  | +      this->obj_->unlock(this->task_); | 
|  | +  } | 
|  | + | 
|  | + private: | 
|  | +  Thin_archive_object_unlocker(const Thin_archive_object_unlocker&); | 
|  | +  Thin_archive_object_unlocker& operator=(const Thin_archive_object_unlocker&); | 
|  | + | 
|  | +  const Task* task_; | 
|  | +  Object* obj_; | 
|  | +}; | 
|  | + | 
|  | // Include an archive member in the link.  OFF is the file offset of | 
|  | // the member header.  WHY is the reason we are including this member. | 
|  | // Return true if we added the member or if we had an error, return | 
|  | @@ -978,6 +1004,10 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, | 
|  | return unconfigured ? false : true; | 
|  | } | 
|  |  | 
|  | +  // If the object is an external member of a thin archive, | 
|  | +  // unlock it when we're done here. | 
|  | +  Thin_archive_object_unlocker unlocker(this->task_, obj); | 
|  | + | 
|  | if (mapfile != NULL) | 
|  | mapfile->report_include_archive_member(obj->name(), sym, why); | 
|  |  | 
|  | @@ -991,31 +1021,21 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, | 
|  |  | 
|  | if (!input_objects->add_object(obj)) | 
|  | { | 
|  | -      // If this is an external member of a thin archive, unlock the | 
|  | -      // file. | 
|  | -      if (obj->offset() == 0) | 
|  | -	obj->unlock(this->task_); | 
|  | delete obj; | 
|  | +      return true; | 
|  | } | 
|  | -  else | 
|  | -    { | 
|  | -      { | 
|  | -	if (layout->incremental_inputs() != NULL) | 
|  | -	  layout->incremental_inputs()->report_object(obj, 0, this, NULL); | 
|  | -	Read_symbols_data sd; | 
|  | -	obj->read_symbols(&sd); | 
|  | -	obj->layout(symtab, layout, &sd); | 
|  | -	obj->add_symbols(symtab, &sd, layout); | 
|  | -      } | 
|  | - | 
|  | -      // If this is an external member of a thin archive, unlock the file | 
|  | -      // for the next task. | 
|  | -      if (obj->offset() == 0) | 
|  | -        obj->unlock(this->task_); | 
|  |  | 
|  | -      this->included_member_ = true; | 
|  | -    } | 
|  | +  if (layout->incremental_inputs() != NULL) | 
|  | +    layout->incremental_inputs()->report_object(obj, 0, this, NULL); | 
|  | + | 
|  | +  { | 
|  | +    Read_symbols_data sd; | 
|  | +    obj->read_symbols(&sd); | 
|  | +    obj->layout(symtab, layout, &sd); | 
|  | +    obj->add_symbols(symtab, &sd, layout); | 
|  | +  } | 
|  |  | 
|  | +  this->included_member_ = true; | 
|  | return true; | 
|  | } | 
|  |  |