summaryrefslogtreecommitdiffstats
path: root/third_party/binutils/unlock-thin.patch
blob: 6a4b6a7c98426044151c3fc9926315cf789db6b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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;
 }